This page detects chrome devtool perfectly [duplicate] - javascript
I am using this little script to find out whether Firebug is open:
if (window.console && window.console.firebug) {
//is open
};
And it works well. Now I was searching for half an hour to find a way to detect whether Google Chrome's built-in web developer console is open, but I couldn't find any hint.
This:
if (window.console && window.console.chrome) {
//is open
};
doesn't work.
EDIT:
So it seems that it is not possible to detect whether the Chrome console is open. But there is a "hack" that works, with some drawbacks:
will not work when console is undocked
will not work when console is open on page load
So, I am gonna choose Unsigned´s answer for now, but if some1 comes up with a brilliant idea, he is welcome to still answer and I change the selected answer! Thanks!
Leaving previous answers below for historical context.
Debugger (2022)
While not fool-proof, this debugger-based approach in another answer does appear to still work.
requestAnimationFrame (Late 2019)
Currently Muhammad Umer's approach works on Chrome 78, with the added advantage of detecting both close and open events.
function toString (2019)
Credit to Overcl9ck's comment on this answer. Replacing the regex /./ with an empty function object still works.
var devtools = function() {};
devtools.toString = function() {
if (!this.opened) {
alert("Opened");
}
this.opened = true;
}
console.log('%c', devtools);
// devtools.opened will become true if/when the console is opened
regex toString (2017-2018)
Since the original asker doesn't seem to be around anymore and this is still the accepted answer, adding this solution for visibility. Credit goes to Antonin Hildebrand's comment on zswang's answer. This solution takes advantage of the fact that toString() is not called on logged objects unless the console is open.
var devtools = /./;
devtools.toString = function() {
if (!this.opened) {
alert("Opened");
}
this.opened = true;
}
console.log('%c', devtools);
// devtools.opened will become true if/when the console is opened
console.profiles (2013)
Update: console.profiles has been removed from Chrome. This solution no longer works.
Thanks to Paul Irish for pointing out this solution from Discover DevTools, using the profiler:
function isInspectOpen() {
console.profile();
console.profileEnd();
if (console.clear) {
console.clear();
}
return console.profiles.length > 0;
}
function showIfInspectIsOpen() {
alert(isInspectOpen());
}
<button onClick="showIfInspectIsOpen()">Is it open?</button>
window.innerHeight (2011)
This other option can detect the docked inspector being opened, after the page loads, but will not be able to detect an undocked inspector, or if the inspector was already open on page load. There is also some potential for false positives.
window.onresize = function() {
if ((window.outerHeight - window.innerHeight) > 100) {
alert('Docked inspector was opened');
}
}
Chrome 65+ (2018)
r = /./
r.toString = function () {
document.title = '1'
}
console.log('%c', r);
demo: https://jsbin.com/cecuzeb/edit?output (Update at 2018-03-16)
package: https://github.com/zswang/jdetects
When printing “Element” Chrome developer tools will get its id
var checkStatus;
var element = document.createElement('any');
element.__defineGetter__('id', function() {
checkStatus = 'on';
});
setInterval(function() {
checkStatus = 'off';
console.log(element);
console.clear();
}, 1000);
Another version (from comments)
var element = new Image();
Object.defineProperty(element, 'id', {
get: function () {
/* TODO */
alert('囧');
}
});
console.log('%cHello', element);
Print a regular variable:
var r = /./;
r.toString = function() {
document.title = 'on';
};
console.log(r);
Very Reliable hack
Basically set a getter on property and log it in console. Apparently the thing gets accessed only when console is open.
https://jsfiddle.net/gcdfs3oo/44/
var checkStatus;
var indicator = document.querySelector('#devtool-status');
var element = new Image();
Object.defineProperty(element, 'id', {
get: function() {
checkStatus='on';
throw new Error("Dev tools checker");
}
});
requestAnimationFrame(function check() {
checkStatus = 'off';
console.dir(element);
indicator.className = checkStatus;
requestAnimationFrame(check);
});
.on{
color:limegreen;
}
.off{
color:red;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.7.1/css/all.css" integrity="sha256-DVK12s61Wqwmj3XI0zZ9MFFmnNH8puF/eRHTB4ftKwk=" crossorigin="anonymous" />
<p>
<ul>
<li>
dev toolbar open: icon is <span class="on">green</span>
</li>
<li>
dev toolbar closed: icon is <span class="off">red</span>
</li>
</ul>
</p>
<div id="devtool-status"><i class="fas fa-7x fa-power-off"></i></div>
<br/>
<p><b>Now press F12 to see if this works for your browser!</b></p>
I created devtools-detect which detects when DevTools is open:
console.log('is DevTools open?', window.devtools.open);
You can also listen to an event:
window.addEventListener('devtoolschange', function (e) {
console.log('is DevTools open?', e.detail.open);
});
It doesn't work when DevTools is undocked. However, works with the Chrome/Safari/Firefox DevTools and Firebug.
------ Update: ------
This is an old question with many great answers that worked for a while. The current best answer as of September 5th 2022 is by #david-fong https://stackoverflow.com/a/68494829/275333
Btw, my answer is still working the same since I've posted it, it's just a bit difficult to make it always accurate. Click on the "Manual Benchmark" link in my demo with the console closed/opened to see what I mean - there is always a big difference.
----------------------
I found a way to tell if the Chrome Console is opened or not.
It’s still a hack but it’s way more accurate and will work whether the console is undocked or not.
Basically running this code with the console closed takes about ~100 microseconds and while the console is opened it takes about twice as much ~200 microseconds.
console.log(1);
console.clear();
(1 millisecond = 1000 microsecond)
I’ve written more about it here.
Demo is here.
console.log(Object.defineProperties(new Error, {
message: {get() {alert('Chrome/Firefox')}},
toString: {value() {(new Error).stack.includes('toString#')&&alert('Safari')}}
}));
Demo: https://jsbin.com/cateqeyono/edit?html,output
There seem to be a few common classes of solutions:
Rely on detecting resizing of the screen when the devtools appear (this doesn't work when the devtools/console are opened as a separate window)
Intercept certain user actions that can bring up the devtools/console such as right click menu, F12, Ctrl+Shift+C, etc. This can't cover UI mechanisms that are in the browser chrome that aren't detectable by the page.
Log something to the console and rely on browser-specific behaviour for lazy, fancy printing. Historically, these seem to not be highly reliable, but they're nice and simple. If you want them to work repeatedly in the same browsing session, you'll probably have to accept some degree of console spam.
Use timing heuristics with the debugger statement. The tricky part is to find a way so that the timers can't get messed up by long running tasks in the event loop queue, and the fact that the debugger statement pauses execution of the thread it runs on. There's also the challenge that regular debugger statements can be disabled by the user on a case-by-case or disable-all basis.
What follows is my solution to the specific problems with the debugger approach. Ie. Avoid false positives when the main thread runs a long task between a heuristic timer, avoid the debugger statement from blocking the main thread, and prevent disabling the debugger statement. Note: I don't think there is a way to prevent a user from disabling all debugger breakpoints, and that is probably for the best.
How It Works
The Chrome browser enters debugging when devtools are open and a thread encounters a debugging statement.
Main thread sends a message to a webworker thread.
Worker thread replies with an opening heartbeat.
Main thread reacts by starting a timer to expect the closing heartbeat.
Worker thread's message handler encounters a debugger statement (optionally wrapped in an eval statement to prevent the user from disabling it).
If devtools are closed, the worker will immediately send an acknowledgement to the main thread, and the main thread will conclude that devtools are closed.
If devtools are opened, the worker will enter a debugging session, and the main thread will notice that the Worker has not responded sufficiently quickly, concluding that the debugger must be open. The main thread will not be blocked by the worker's debugging session, but it's timeout response will be blocked by any heavy processing in the main thread ahead of it in the event queue.
I've published a reference implementation (authored by me) here on GitHub, and a demo here.
Pros
Unlike screen-size-change-detection approaches, this works when the console is in a separate window.
Unlike user-action-interception approaches, this works regardless of what user action brings up the console.
Unlike console.log approaches, this can work for multiple open-closes of the console without spamming the console with messages.
Unlike basic timer-debugger approaches, the detection should never trigger false positives due to busy threads (main thread, or other workers), the debugger statement is in the worker instead of the main thread, so the main thread won't get blocked, and the eval-debugger statement prevents disabling that specific debugger statement.
Cons
The user can disable all breakpoints, which will disable this method of detection.
The eval-wrapped debugger statement won't work on sites which disable eval via their Content Security Policy, in which case only a regular debugger statement can be used.
I found new methods work at Chrome 89
Using console.profile, setInterval and function toString
var devtools = function() {};
devtools.toString = function() {
alert('NOPE!!')
return '-'
}
setInterval(()=>{
console.profile(devtools)
console.profileEnd(devtools)
}, 1000)
In safari, it doesn't works.
Below chrome 89, i can't check whether it works.
The Chrome developer tools is really just a part of WebKit's WebCore library. So this question applies to Safari, Chrome, and any other WebCore consumers.
If a solution exists, it'll be based off a difference in the DOM when the WebKit web inspector is open and when it's closed. Unfortunately, this is a kind of a chicken and egg problem because we can't use the inspector to observe the DOM when the inspector is closed.
What you may be able to do is write a bit of JavaScript to dump the entire DOM tree. Then run it once when the inspector is open, and once when the inspector is closed. Any difference in the DOM is probably a side-effect of the web inspector, and we may be able to use it to test if the user is inspecting or not.
This link is a good start for a DOM dumping script , but you'll want to dump the entire DOMWindow object, not just document.
Update:
Looks like there's a way to do this now. Check out Chrome Inspector Detector
There is a tricky way to check it for extensions with 'tabs' permission:
chrome.tabs.query({url:'chrome-devtools://*/*'}, function(tabs){
if (tabs.length > 0){
//devtools is open
}
});
Also you can check if it open for your page:
chrome.tabs.query({
url: 'chrome-devtools://*/*',
title: '*example.com/your/page*'
}, function(tabs){ ... })
I wrote a blog post about this: http://nepjua.org/check-if-browser-console-is-open/
It can detect whether it's docked or undocked
function isConsoleOpen() {
var startTime = new Date();
debugger;
var endTime = new Date();
return endTime - startTime > 100;
}
$(function() {
$(window).resize(function() {
if(isConsoleOpen()) {
alert("You're one sneaky dude, aren't you ?")
}
});
});
var div = document.createElement('div');
Object.defineProperty(div,'id',{get:function(){
document.title = 'xxxxxx'
}});
setTimeout(()=>console.log(div),3000)
Muhammad Umer's approach worked for me, and I'm using React, so I decided to make a hooks solution:
const useConsoleOpen = () => {
const [consoleOpen, setConsoleOpen] = useState(true)
useEffect(() => {
var checkStatus;
var element = new Image();
Object.defineProperty(element, "id", {
get: function () {
checkStatus = true;
throw new Error("Dev tools checker");
},
});
requestAnimationFrame(function check() {
checkStatus = false;
console.dir(element); //Don't delete this line!
setConsoleOpen(checkStatus)
requestAnimationFrame(check);
});
}, []);
return consoleOpen
}
NOTE: When I was messing with it, it didn't work for the longest time and I couldn't figure out why. I had deleted console.dir(element); which is critical to how it works. I delete most non-descriptive console actions since they just take up space and aren't usually necessary to the function, so that was why it wasn't working for me.
To use it:
import React from 'react'
const App = () => {
const consoleOpen = useConsoleOpen()
return (
<div className="App">
<h1>{"Console is " + (consoleOpen ? "Open" : "Closed")}</h1>
</div>
);
}
I hope this helps anyone using React. If anyone wants to expand on this, I would like to be able stop the infinite loop at some point (since I don't use this in every component) and to find a way to keep the console clean.
Javascript Detect Developer Tools Console Opening
Working from 2/2/2022
Chrome Version 97 (Developer Tools Undocked/Docked/Keyboard shortcuts)
Edge Version 97 (Developer Tools Undocked/Docked/Keyboard shortcuts)
FireFox Version 96.0.03 (Developer Tools Undocked/Docked/Keyboard shortcuts)
Safari ?
FireBug Detection (Developer Tools)
// Prevent Right Click (Optional)
document.addEventListener('contextmenu', function(event) {
event.preventDefault();
}, true);
// DevTools Opened Script
function DevToolsOpened() {
alert("Developer Tools Opened");
}
// Detect DevTools (Chrome/Edge)
// https://stackoverflow.com/a/67148898/9498503 (SeongJun)
var devtools = function() {};
devtools.toString = function() {
DevToolsOpened();
return '-';
}
setInterval(()=>{
console.profile(devtools);
console.profileEnd(devtools);
if (console.clear) {
console.clear();
}
}, 1000);
// Detect DevTools (FireFox)
if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1){
// Detect Resize (Chrome/Firefox/Edge Works) but (Triggers on Zoom In Chrome and Zoom Out FireFox)
window.onresize = function() {
if ((window.outerHeight - window.innerHeight) > 100 || (window.outerWidth - window.innerWidth) > 100) {
DevToolsOpened();
}
}
}
// Detect Fire Bug
if (window.console && window.console.firebug || console.assert(1) === '_firebugIgnore') {
DevToolsOpened();
};
// Detect Key Shortcuts
// https://stackoverflow.com/a/65135979/9498503 (hlorand)
window.addEventListener('keydown', function(e) {
if (
// CMD + Alt + I (Chrome, Firefox, Safari)
e.metaKey == true && e.altKey == true && e.keyCode == 73 ||
// CMD + Alt + J (Chrome)
e.metaKey == true && e.altKey == true && e.keyCode == 74 ||
// CMD + Alt + C (Chrome)
e.metaKey == true && e.altKey == true && e.keyCode == 67 ||
// CMD + Shift + C (Chrome)
e.metaKey == true && e.shiftKey == true && e.keyCode == 67 ||
// Ctrl + Shift + I (Chrome, Firefox, Safari, Edge)
e.ctrlKey == true && e.shiftKey == true && e.keyCode == 73 ||
// Ctrl + Shift + J (Chrome, Edge)
e.ctrlKey == true && e.shiftKey == true && e.keyCode == 74 ||
// Ctrl + Shift + C (Chrome, Edge)
e.ctrlKey == true && e.shiftKey == true && e.keyCode == 67 ||
// F12 (Chome, Firefox, Edge)
e.keyCode == 123 ||
// CMD + Alt + U, Ctrl + U (View source: Chrome, Firefox, Safari, Edge)
e.metaKey == true && e.altKey == true && e.keyCode == 85 ||
e.ctrlKey == true && e.keyCode == 85
) {
DevToolsOpened();
}
});
Also you can try this: https://github.com/sindresorhus/devtools-detect
// check if it's open
console.log('is DevTools open?', window.devtools.open);
// check it's orientation, null if not open
console.log('and DevTools orientation?', window.devtools.orientation);
// get notified when it's opened/closed or orientation changes
window.addEventListener('devtoolschange', function (e) {
console.log('is DevTools open?', e.detail.open);
console.log('and DevTools orientation?', e.detail.orientation);
});
If you are developers who are doing stuff during development. Check out this Chrome extension. It helps you detect when Chrome Devtoos is opened or closed.
https://chrome.google.com/webstore/detail/devtools-status-detector/pmbbjdhohceladenbdjjoejcanjijoaa?authuser=1
This extension helps Javascript developers detect when Chrome Devtools is open or closed on current page.
When Chrome Devtools closes/opens, the extension will raise a event named 'devtoolsStatusChanged' on window.document element.
This is example code:
function addEventListener(el, eventName, handler) {
if (el.addEventListener) {
el.addEventListener(eventName, handler);
} else {
el.attachEvent('on' + eventName,
function() {
handler.call(el);
});
}
}
// Add an event listener.
addEventListener(document, 'devtoolsStatusChanged', function(e) {
if (e.detail === 'OPENED') {
// Your code when Devtools opens
} else {
// Your code when Devtools Closed
}
});
Some answers here will stop working in Chrome 65. Here's a timing attack alternative that works pretty reliably in Chrome, and is much harder to mitigate than the toString() method. Unfortunately it's not that reliable in Firefox.
addEventListener("load", () => {
var baseline_measurements = [];
var measurements = 20;
var warmup_runs = 3;
const status = document.documentElement.appendChild(document.createTextNode("DevTools are closed"));
const junk = document.documentElement.insertBefore(document.createElement("div"), document.body);
junk.style.display = "none";
const junk_filler = new Array(1000).join("junk");
const fill_junk = () => {
var i = 10000;
while (i--) {
junk.appendChild(document.createTextNode(junk_filler));
}
};
const measure = () => {
if (measurements) {
const baseline_start = performance.now();
fill_junk();
baseline_measurements.push(performance.now() - baseline_start);
junk.textContent = "";
measurements--;
setTimeout(measure, 0);
} else {
baseline_measurements = baseline_measurements.slice(warmup_runs); // exclude unoptimized runs
const baseline = baseline_measurements.reduce((sum, el) => sum + el, 0) / baseline_measurements.length;
setInterval(() => {
const start = performance.now();
fill_junk();
const time = performance.now() - start;
// in actual usage you would also check document.hasFocus()
// as background tabs are throttled and get false positives
status.data = "DevTools are " + (time > 1.77 * baseline ? "open" : "closed");
junk.textContent = "";
}, 1000);
}
};
setTimeout(measure, 300);
});
As for Chrome/77.0.3865.75 a version of 2019 not works. toString invokes immediately without Inspector opening.
const resultEl = document.getElementById('result')
const detector = function () {}
detector.toString = function () {
resultEl.innerText = 'Triggered'
}
console.log('%c', detector)
<div id="result">Not detected</div>
use this package isDevToolsOpened() function from the package dev-tools-monitor
which works as expected in all browsers except for firefox.
Force a colorized welcome message, each time the console is opened.
// Force a colorized welcome message
// each time the console is opened.
(() => {
w = new Function()
w.toString = () => { (!this.z) ? console.log("%cWelcome to the console\n %cMaster password:\n %c window.password = ' ... ':", "color: white; font-size: 20px; background-color: blue", "color: white; font-size: 16px; background-color: red;margin 20px 0", "background: #222; color: #bada55") : this.z = true
}
console.log('%c', w)
})()
You can catch the event of opening the dev. tools by adding event listeners to the keyboard shortcuts with which it opens. This is not a "hack" and it works 100% of the time.
The only case it won't catch is when the user opens it manually with mouse. So it is a "partial solution" perhaps it is useful for somebody.
<script>
function devToolsOpened(e){
alert("devtools opened");
// uncomment to prevent opening dev.tools:
// e.preventDefault();
}
window.addEventListener('keydown', function(e) {
if (
// CMD + Alt + I (Chrome, Firefox, Safari)
e.metaKey == true && e.altKey == true && e.keyCode == 73 ||
// CMD + Alt + J (Chrome)
e.metaKey == true && e.altKey == true && e.keyCode == 74 ||
// CMD + Alt + C (Chrome)
e.metaKey == true && e.altKey == true && e.keyCode == 67 ||
// CMD + Shift + C (Chrome)
e.metaKey == true && e.shiftKey == true && e.keyCode == 67 ||
// Ctrl + Shift + I (Chrome, Firefox, Safari, Edge)
e.ctrlKey == true && e.shiftKey == true && e.keyCode == 73 ||
// Ctrl + Shift + J (Chrome, Edge)
e.ctrlKey == true && e.shiftKey == true && e.keyCode == 74 ||
// Ctrl + Shift + C (Chrome, Edge)
e.ctrlKey == true && e.shiftKey == true && e.keyCode == 67 ||
// F12 (Chome, Firefox, Edge)
e.keyCode == 123 ||
// CMD + Alt + U, Ctrl + U (View source: Chrome, Firefox, Safari, Edge)
e.metaKey == true && e.altKey == true && e.keyCode == 85 ||
e.ctrlKey == true && e.keyCode == 85
){
devToolsOpened(e);
}
});
</script>
Keyboard shortcuts to open Developer Tools:
Chrome: https://developers.google.com/web/tools/chrome-devtools/shortcuts
Firefox: https://developer.mozilla.org/hu/docs/Tools
Safari: https://developer.apple.com/library/archive/documentation/AppleApplications/Conceptual/Safari_Developer_Guide/KeyboardShortcuts/KeyboardShortcuts.html
Edge: https://learn.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/shortcuts
Timing solution (works for docked and undocked)
It is a bit intrusive but not as much as the debugger trap
var opened = false;
var lastTime = Date.now();
const interval = 50;
const threshold = 30;
setInterval(() => {
let delta = Date.now() - lastTime;
if (delta > interval + threshold) {
document.title = "P3nis";
opened = true;
}
lastTime = Date.now();
if (!opened) {
debugger;
}
}, interval)
When a browser's DevTools is open, breakpoints marked by 'debugger;' will be attached as long as you don't deactivate breakpoints.
So here is the code to check if debugger is enabled:
let workerUrl = 'data:application/javascript;base64,' + btoa(`
self.addEventListener('message', (e) => {
if(e.data==='hello'){
self.postMessage('hello');
}
debugger;
self.postMessage('');
});
`);
function checkIfDebuggerEnabled() {
return new Promise((resolve) => {
let fulfilled = false;
let worker = new Worker(workerUrl);
worker.onmessage = (e) => {
let data = e.data;
if (data === 'hello') {
setTimeout(() => {
if (!fulfilled) {
resolve(true);
worker.terminate();
}
}, 1);
} else {
fulfilled = true;
resolve(false);
worker.terminate();
}
};
worker.postMessage('hello');
});
}
checkIfDebuggerEnabled().then((result) => {
if (result) {
alert('browser DevTools is open');
}else{
alert('browser DevTools is not open, unless you have deactivated breakpoints');
}
});
Note: if CSP is used then you need either to add worker-src 'unsafe-inline' to CSP policy or to move worker source code above to a CSP-allowed resource and change workerUrl to that resource.
Best way to have Debug-Mode on/off feature is to set a flag 'debugMode'='off' in localStorage by default -
localStorage.setItem('debugMode', 'off');
Then, change it in Local Storage of browser manually to 'on' while development -
Then use below condition in code to do differrent action if it's 'on' -
if(localStorage.getItem('debugMode') === 'on'){
//do something 1
}else {
//do something 2
}
Related
Detect mouse on touch screen device
I use the following code to detect whether the device is a touch device or not: var isTouchDevice = 'ontouchstart' in window || navigator.msMaxTouchPoints; if(isTouchDevice) { $('body').addClass('yes-touch'); } else { $('body').addClass('no-touch'); } I use this to only show :hover states when it is NOT a touch device (as most touch devices interpret a tap as a hover). .no-touch .element:hover { color: red; } The problem is, one of our PCs in the office is an all-on-one touch screen PC, which means that when using a mouse the hover states don't occur. Is there a way to work out whether a mouse is being used on a touch screen device? In other words, it should have the no-touch class applied when the mouse is being used and the yes-touch class applied when the touch screen is being used.
As of today, there is no foolproof ironclad way of doing it. The modernizr folks, pretty much the experts in feature detection, recently had this to say about it: https://github.com/Modernizr/Modernizr/issues/869#issuecomment-57891034 The end result of all of this is that you cannot detect a mouse use in a way that would conform to the level of reliability that Modernizr is credited with. For our intents and purposes, it is a undetectable. If you, future traveler, wish to attempt to detect a mouse user, then the following is the best guide I can offer. Don't. Seriously. Just because a user has a "mouse" doesn't mean that they don't have multiple other forms of input. You should try really hard to avoid making any kind of UI/UX decision that changes based upon the idea of a mouse user being diametrically opposed to a touchscreen user (or any other kind, for that matter). Make things universal. If you have to, and only care about IE 10 and 11, then IE's PointerEvent would be worth checking out. Support is abysmal, outside of those two (and presumably future IE versions). You can attach a listener for a 'hover' event on the body, and if it is true, then the user probably has a mouse. The drawback with this approach include touch events briefly firing hover events on tap/touch, so you could get false positives. sniff for mobile user agents. This is a bad idea, and goes against the very core of Modernizr. Please don't do it. So to me #1 pretty much sums it up. However, that answers your question but doesn't give you a solution. You mention "one of our PC's in the office..." Is this by chance an internal only application? I've occasionally run across situations where internal special use or one off pages may require some individual treatment for whatever reason (like one of our employees having a touch based AIO with a mouse attached). What I'll do then is append a ?hasmouse onto the end of the url and give the user that link to bookmark. Then inside javascript after your var isTouchDevice but before your if, insert this code to undo it: if (location.search == '?hasmouse') { isTouchDevice = false; } Again, thats sort of a no frills way for just internal use.
I have been using this for a while and it seems to work reliably. I wounder if it's worth it sometimes, but it does work. The idea here is to capture actual touchdown events to trigger touch mode and use mousemove to trigger mouse mode. The problem is IE does not trigger touch events, but pointer events. The great thing about pointer events is you can check if it's mouse or touch! The problem is all other browsers fire a fake mousemove just after a touch event. It's truly maddening! You can see it work on this codepen //First check if this is a touch device: this.isTouch = 'ontouchstart' in window || (navigator.msMaxTouchPoints > 0); // Some vars we'll need later var lastTouch = 0 var lastCheck = 0 //Then set up our event listeners: function initEvents() { //handle touch/mouse devices detect mouse so that touch is toggled off if (this.isTouch) { $(document).on(" touchstart mousemove " + msPointerEvent('move'), function(e) { e = e.originalEvent //browser has pointer events var pe = window.PointerEvent || window.MSPointerEvent // handle ie pointer events (polyfill functions are at bottom of answer) if (e.type == msPointerEvent('move')) { var touchEvent = msPointerType(e) == 'touch' if (touchEvent) lastTouch = e.timeStamp; if (!this.isTouch && touchEvent) return setupTouch.call(this, true) else if (this.isTouch && !touchEvent) return setupTouch.call(this, false) } // Handle all other browser touch events if (e.type == "touchstart") { console.log('touchstart fired') lastTouch = e.timeStamp; if (!this.isTouch) setupTouch.call(this, true); } // test mouse move and set up mouse mode if real else if (!pe && e.type == "mousemove" && this.isTouch) { if (realMouseDown.call(this, e)) { setupTouch.call(this, false) } } }.bind(this)); } } initEvents() // Here is where we get clever. It turns out that the fake mousemove will fire in less than 500ms of the touch so we use that to detect fakes. Then of course do something special for IE: function realMouseDown(e) { var touchDif = e.timeStamp - lastTouch var mouseDif = e.timeStamp - lastCheck // false mouse event will get fired within 500ms of a touch (touchDif > 500) // (required for all browsers false mouse after touch event) var real = touchDif > 500 lastCheck = e.timeStamp; console.log('real=', real, ' mDif ='+mouseDif, ' tDif ='+touchDif) return real } // Now for some IE polyfill because they cant seem to make up their mind what to do. // IE pointer event polyfill function msPointerEvent(type) { var n = "" if (window.PointerEvent) // IE 11 n = 'pointer' + type else if (window.MSPointerEvent) // IE 10 n = 'MSPointer' + type[0].toUpperCase() + type.substr(1); return n } // IE pointer type polyfill function msPointerType(e) { var pt = ['zero', 'one', 'touch', 'pen', 'mouse'] return typeof e.pointerType == 'string' ? e.pointerType : pt[e.pointerType] } // And finally do what you need... // make required changes for touch / mouse var $output = $('#output') function setupTouch(state) { console.log('TouchMode=', state) if (state) this.isTouch = true else this.isTouch = false $output.html('Touch mode changed to = '+state) } //First check if this is a touch device: this.isTouch = 'ontouchstart' in window || (navigator.msMaxTouchPoints > 0); // Some vars we'll need later var lastTouch = 0 var lastCheck = 0 //Then set up our event listeners: function initEvents() { //handle touch/mouse devices detect mouse so that touch is toggled off if (this.isTouch) { $(document).on(" touchstart mousemove " + msPointerEvent('move'), function(e) { e = e.originalEvent //browser has pointer events var pe = window.PointerEvent || window.MSPointerEvent // handle ie pointer events (polyfill functions are at bottom of answer) if (e.type == msPointerEvent('move')) { var touchEvent = msPointerType(e) == 'touch' if (touchEvent) lastTouch = e.timeStamp; if (!this.isTouch && touchEvent) return setupTouch.call(this, true) else if (this.isTouch && !touchEvent) return setupTouch.call(this, false) } // Handle all other browser touch events else if (e.type == "touchstart") { console.log('touchstart fired') lastTouch = e.timeStamp; if (!this.isTouch) setupTouch.call(this, true); } // test mouse move and set up mouse mode if real else if (!pe && e.type == "mousemove" && this.isTouch) { if (realMouseDown.call(this, e)) { setupTouch.call(this, false) } } }.bind(this)); } } initEvents() // Here is where we get clever. It turns out that the fake mousemove will fire in less than 500ms of the touch so we use that to detect fakes: function realMouseDown(e) { var touchDif = e.timeStamp - lastTouch var mouseDif = e.timeStamp - lastCheck // false mouse event will get fired within 500ms of a touch (touchDif > 500) // (required for all browsers false mouse after touch event) var real = touchDif > 500 lastCheck = e.timeStamp; console.log('real=', real, ' mDif =' + mouseDif, ' tDif =' + touchDif) return real } // IE pointer event polyfill function msPointerEvent(type) { var n = "" if (window.PointerEvent) // IE 11 n = 'pointer' + type else if (window.MSPointerEvent) // IE 10 n = 'MSPointer' + type[0].toUpperCase() + type.substr(1); return n } // IE pointer type polyfill function msPointerType(e) { var pt = ['zero', 'one', 'touch', 'pen', 'mouse'] return typeof e.pointerType == 'string' ? e.pointerType : pt[e.pointerType] } // make required changes for touch / mouse var $output = $('#output') function setupTouch(state) { console.log('TouchMode=', state) if (state) { this.isTouch = true $output.addClass('is-touch') } else { this.isTouch = false $output.removeClass('is-touch') } $output.html('Touch mode changed to = ' + state) } body { pointer-evetns: none; } #output.is-touch { background-color: blue; color: white; } <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <div id="output"> Touch or movethe mose on the result window to change the TouchMode state. </div>
You can check for type of Pointer Event, that attached to Your object. Please see example for hover below: $('.element').on('pointerenter', function (e) { if (e.pointerType == 'mouse') { $(this).addClass('hover'); } }).on('pointerleave', function (e) { if (e.pointerType == 'mouse') { $(this).removeClass('hover'); } }); And use your css: .element.hover { color: red; }
Check for Touch device with Javascript
I have 3 buttons with hover states which makes a little tooltip appear to describe the button. They work fine but on touchs screen they do not disappear after the user clicks on the button. So I've tried a few js scripts for checking if a device is a touch device or not. They almost work but they also when I test on IE11 it also gets detected as a touch device. Chrome & Firefox do not get mistaken as a touch device. Any sugestions? Her is what I've tried /***************************** TOUCH DEVICES HOVER FIX START ****************************/ // http://stackoverflow.com/a/4819886/1814446 function isTouchDevice() { return 'ontouchstart' in window // works on most browsers || 'onmsgesturechange' in window; // works on ie10 }; // http://www.stucox.com/blog/you-cant-detect-a-touchscreen/#poke-it var hasTouch; window.addEventListener('touchstart', function setHasTouch () { hasTouch = true; // Remove event listener once fired, otherwise it'll kill scrolling // performance window.removeEventListener('touchstart', setHasTouch); }, false); // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.js define(['Modernizr', 'prefixes', 'testStyles'], function( Modernizr, prefixes, testStyles ) { // Chrome (desktop) used to lie about its support on this, but that has since been rectified: http://crbug.com/36415 Modernizr.addTest('touchevents', function() { var bool; if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) { bool = true; } else { var query = ['#media (',prefixes.join('touch-enabled),('),'heartz',')','{#modernizr{top:9px;position:absolute}}'].join(''); testStyles(query, function( node ) { bool = node.offsetTop === 9; }); } return bool; }); }); if(bool===true) { console.log('Touch Device'); //your logic for touch device jQ( "#btn-1, #btn-2, #btn-3" ).click(function() { jQ("#btn-1 .tooltip").css('opacity', '0'); jQ("#btn-2 .tooltip").css('opacity', '0'); jQ("#btn-3 .tooltip").css('opacity', '0'); }); } else { //your logic for non touch device }
For IE10+ you can utilize "window.navigator.msMaxTouchPoints" example code function isIETouch () { return window.navigator.msMaxTouchPoints == undefined ? false : window.navigator.msMaxTouchPoints; }
How can we programmatically enter and exit the fullscreen mode in javascript?
Here's documentation on exiting fullscreen mode. I used this code that I learnd to make the browser go fullscreen (it works), but my attempts to modify a version of it to exit fullscreen failed. Dealing with these non-standard APIs is a little tricky, with each browser implementing it a bit differently. Here's the code: // Bring the page into full-screen mode - Works! function requestFullScreen(element) { // Supports most browsers and their versions. var requestMethod = element.requestFullScreen || element.webkitRequestFullScreen || element.mozRequestFullScreen || element.msRequestFullScreen; if (requestMethod) { requestMethod.call(element); } else if ( typeof window.ActiveXObject !== "undefined") { var wscript = new ActiveXObject("WScript.Shell"); if (wscript !== null) { wscript.SendKeys("{F11}"); } } } // Exit fullscreen - Doesn't work! function exitFullScreen(element){ var requestMethod = element.exitFullscreen || element.mozCancelFullScreen || element.webkitExitFullscreen || element.msExitFullscreen; if (requestMethod) { requestMethod(); } else { console.log("Oops. Request method false."); } } And the calls: var $fullscreenButton = $("#fullscreen-button"); var $smallscreenButton = $("#smallscreen-button"); $fullscreenButton.on("click", function() { var elem = document.body; // Make the body go full screen. requestFullScreen(elem); }); $smallscreenButton.on("click", function() { var elem = document.body; // Exit full screen. exitFullScreen(elem); }); What's wrong with the exitFullScreen function? How can I fix it? Edit: I'm working on a JSFiddle for this! By "Doesn't work", I meant that it outputs "Oops. Request method false." I'm calling the function exitFullScreen() with the parameter document.body JSFiddle: While the full screen request function works for me in the browser normally, I could not get it to work in JSFiddle, and I'm unsure whether this is because of my own mistake, or something to do with JSFiddle.
For entering the fullscreen there were some issues with the capitalization. For the exiting you need to call it on the document and not on the body, and you also need to apply it correctly instead of calling the reference to the method.. so requestMethod.call(element); for exiting as well. See demo at http://jsfiddle.net/gaby/FGX72/show (tested on latest IE/Chrome/FireFox)
can not disable Ctrl+O by JavaScript in IE 11
I'm trying to disable Ctrl+o key combination in IE, the following code works fine in all IE versions except IE 11 unless I do an alert as you see in code below: document.onkeydown = function(event) { var x = event.keyCode; console.log(event.keyCode); console.log(event.ctrlKey); if ((x == 79) && (event.ctrlKey)) { if(navigator.userAgent.match(/rv:11.0/i)){ alert('Disabled'); } event.cancelBubble = true; event.returnValue = false; event.keyCode = 0; event.stopPropagation(); event.preventDefault(); return false; } }; I was wondering if anyone else is experiencing the same issue and they have solved it. :-) Thanks. Alex
I have no good solution unfortunately, but have created a case with Microsoft, and made a jfiddle that demonstrates the issue. The only way we have found around this is the use of the: <meta http-equiv="X-UA-Compatible" content="IE=7"> header, but there's no telling when support for that will go away - not to mention the obvious side-effects of running in IE7 mode. Some additional notes: Although the interception works natively on IE8 and IE9, only the IE=7 UA mode works A page reload is required for the header to take effect, whether it is in the page or returned in the server response i.e. you cannot selectively jump in an out of IE7 mode in a single page app Here is a link to the standards that IE11 was built against: http://www.w3.org/TR/DOM-Level-3-Events/#KeyboardEvent-supplemental-interface Fiddle: http://jsfiddle.net/bw5sLd15/1/ // The kitchen sink function killKey( event ) { event.cancelBubble = true; event.bubbles = false; event.returnValue = false; event.stopPropagation(); event.stopImmediatePropagation(); event.preventDefault(); return false; }
I came to the same conclusion as Alex & Max. In my specific use case, forcing compatibility mode would break other features. I believe that in most cases a confirm dialog is the best workaround, as it still feels somewhat natural to the user - save for the extra step involved. http://jsfiddle.net/dperish/sp72c0wt/3/ HTML: <h1>Demonstration of IE11 event bubbling issue</h1> <label>Enable Workaround<input type="checkbox" id="enableWorkaround"></label> <p>Pressing CTRL-P or CTRL-O should NOT show the default open/print dialogs. The only workaround seems to be to interrupt the main thread either with alert(), confirm(), or by hitting a breakpoint in a debugger. </p> <p>Unfortunately, a synchronous/blocking XHR call was not useful for this purpose. Nor was using the browser-specific showModalDialog.</p> <div id="output"></div> Javascript: function onKeyDown(e) { e = e || window.event; if ((e.keyCode === 79 || e.keyCode === 80) && e.ctrlKey) { e.preventDefault(); e.stopPropagation(); e.returnValue = false; if ($("#enableWorkaround").is(":checked")) { if (confirm("Run some custom method?")) { customMethod(e.keyCode); } } else { customMethod(e.keyCode); } return false; } } function customMethod(x) { $("#output").append("<p>CustomMethod Says: KeyCode = " + x + "</p>"); return false; } $(document).ready(function() { $(document).on("keydown", function (e) { onKeyDown(e); }); });
Find out whether Chrome console is open
I am using this little script to find out whether Firebug is open: if (window.console && window.console.firebug) { //is open }; And it works well. Now I was searching for half an hour to find a way to detect whether Google Chrome's built-in web developer console is open, but I couldn't find any hint. This: if (window.console && window.console.chrome) { //is open }; doesn't work. EDIT: So it seems that it is not possible to detect whether the Chrome console is open. But there is a "hack" that works, with some drawbacks: will not work when console is undocked will not work when console is open on page load So, I am gonna choose Unsigned´s answer for now, but if some1 comes up with a brilliant idea, he is welcome to still answer and I change the selected answer! Thanks!
Leaving previous answers below for historical context. Debugger (2022) While not fool-proof, this debugger-based approach in another answer does appear to still work. requestAnimationFrame (Late 2019) Currently Muhammad Umer's approach works on Chrome 78, with the added advantage of detecting both close and open events. function toString (2019) Credit to Overcl9ck's comment on this answer. Replacing the regex /./ with an empty function object still works. var devtools = function() {}; devtools.toString = function() { if (!this.opened) { alert("Opened"); } this.opened = true; } console.log('%c', devtools); // devtools.opened will become true if/when the console is opened regex toString (2017-2018) Since the original asker doesn't seem to be around anymore and this is still the accepted answer, adding this solution for visibility. Credit goes to Antonin Hildebrand's comment on zswang's answer. This solution takes advantage of the fact that toString() is not called on logged objects unless the console is open. var devtools = /./; devtools.toString = function() { if (!this.opened) { alert("Opened"); } this.opened = true; } console.log('%c', devtools); // devtools.opened will become true if/when the console is opened console.profiles (2013) Update: console.profiles has been removed from Chrome. This solution no longer works. Thanks to Paul Irish for pointing out this solution from Discover DevTools, using the profiler: function isInspectOpen() { console.profile(); console.profileEnd(); if (console.clear) { console.clear(); } return console.profiles.length > 0; } function showIfInspectIsOpen() { alert(isInspectOpen()); } <button onClick="showIfInspectIsOpen()">Is it open?</button> window.innerHeight (2011) This other option can detect the docked inspector being opened, after the page loads, but will not be able to detect an undocked inspector, or if the inspector was already open on page load. There is also some potential for false positives. window.onresize = function() { if ((window.outerHeight - window.innerHeight) > 100) { alert('Docked inspector was opened'); } }
Chrome 65+ (2018) r = /./ r.toString = function () { document.title = '1' } console.log('%c', r); demo: https://jsbin.com/cecuzeb/edit?output (Update at 2018-03-16) package: https://github.com/zswang/jdetects When printing “Element” Chrome developer tools will get its id var checkStatus; var element = document.createElement('any'); element.__defineGetter__('id', function() { checkStatus = 'on'; }); setInterval(function() { checkStatus = 'off'; console.log(element); console.clear(); }, 1000); Another version (from comments) var element = new Image(); Object.defineProperty(element, 'id', { get: function () { /* TODO */ alert('囧'); } }); console.log('%cHello', element); Print a regular variable: var r = /./; r.toString = function() { document.title = 'on'; }; console.log(r);
Very Reliable hack Basically set a getter on property and log it in console. Apparently the thing gets accessed only when console is open. https://jsfiddle.net/gcdfs3oo/44/ var checkStatus; var indicator = document.querySelector('#devtool-status'); var element = new Image(); Object.defineProperty(element, 'id', { get: function() { checkStatus='on'; throw new Error("Dev tools checker"); } }); requestAnimationFrame(function check() { checkStatus = 'off'; console.dir(element); indicator.className = checkStatus; requestAnimationFrame(check); }); .on{ color:limegreen; } .off{ color:red; } <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.7.1/css/all.css" integrity="sha256-DVK12s61Wqwmj3XI0zZ9MFFmnNH8puF/eRHTB4ftKwk=" crossorigin="anonymous" /> <p> <ul> <li> dev toolbar open: icon is <span class="on">green</span> </li> <li> dev toolbar closed: icon is <span class="off">red</span> </li> </ul> </p> <div id="devtool-status"><i class="fas fa-7x fa-power-off"></i></div> <br/> <p><b>Now press F12 to see if this works for your browser!</b></p>
I created devtools-detect which detects when DevTools is open: console.log('is DevTools open?', window.devtools.open); You can also listen to an event: window.addEventListener('devtoolschange', function (e) { console.log('is DevTools open?', e.detail.open); }); It doesn't work when DevTools is undocked. However, works with the Chrome/Safari/Firefox DevTools and Firebug.
------ Update: ------ This is an old question with many great answers that worked for a while. The current best answer as of September 5th 2022 is by #david-fong https://stackoverflow.com/a/68494829/275333 Btw, my answer is still working the same since I've posted it, it's just a bit difficult to make it always accurate. Click on the "Manual Benchmark" link in my demo with the console closed/opened to see what I mean - there is always a big difference. ---------------------- I found a way to tell if the Chrome Console is opened or not. It’s still a hack but it’s way more accurate and will work whether the console is undocked or not. Basically running this code with the console closed takes about ~100 microseconds and while the console is opened it takes about twice as much ~200 microseconds. console.log(1); console.clear(); (1 millisecond = 1000 microsecond) I’ve written more about it here. Demo is here.
console.log(Object.defineProperties(new Error, { message: {get() {alert('Chrome/Firefox')}}, toString: {value() {(new Error).stack.includes('toString#')&&alert('Safari')}} })); Demo: https://jsbin.com/cateqeyono/edit?html,output
There seem to be a few common classes of solutions: Rely on detecting resizing of the screen when the devtools appear (this doesn't work when the devtools/console are opened as a separate window) Intercept certain user actions that can bring up the devtools/console such as right click menu, F12, Ctrl+Shift+C, etc. This can't cover UI mechanisms that are in the browser chrome that aren't detectable by the page. Log something to the console and rely on browser-specific behaviour for lazy, fancy printing. Historically, these seem to not be highly reliable, but they're nice and simple. If you want them to work repeatedly in the same browsing session, you'll probably have to accept some degree of console spam. Use timing heuristics with the debugger statement. The tricky part is to find a way so that the timers can't get messed up by long running tasks in the event loop queue, and the fact that the debugger statement pauses execution of the thread it runs on. There's also the challenge that regular debugger statements can be disabled by the user on a case-by-case or disable-all basis. What follows is my solution to the specific problems with the debugger approach. Ie. Avoid false positives when the main thread runs a long task between a heuristic timer, avoid the debugger statement from blocking the main thread, and prevent disabling the debugger statement. Note: I don't think there is a way to prevent a user from disabling all debugger breakpoints, and that is probably for the best. How It Works The Chrome browser enters debugging when devtools are open and a thread encounters a debugging statement. Main thread sends a message to a webworker thread. Worker thread replies with an opening heartbeat. Main thread reacts by starting a timer to expect the closing heartbeat. Worker thread's message handler encounters a debugger statement (optionally wrapped in an eval statement to prevent the user from disabling it). If devtools are closed, the worker will immediately send an acknowledgement to the main thread, and the main thread will conclude that devtools are closed. If devtools are opened, the worker will enter a debugging session, and the main thread will notice that the Worker has not responded sufficiently quickly, concluding that the debugger must be open. The main thread will not be blocked by the worker's debugging session, but it's timeout response will be blocked by any heavy processing in the main thread ahead of it in the event queue. I've published a reference implementation (authored by me) here on GitHub, and a demo here. Pros Unlike screen-size-change-detection approaches, this works when the console is in a separate window. Unlike user-action-interception approaches, this works regardless of what user action brings up the console. Unlike console.log approaches, this can work for multiple open-closes of the console without spamming the console with messages. Unlike basic timer-debugger approaches, the detection should never trigger false positives due to busy threads (main thread, or other workers), the debugger statement is in the worker instead of the main thread, so the main thread won't get blocked, and the eval-debugger statement prevents disabling that specific debugger statement. Cons The user can disable all breakpoints, which will disable this method of detection. The eval-wrapped debugger statement won't work on sites which disable eval via their Content Security Policy, in which case only a regular debugger statement can be used.
I found new methods work at Chrome 89 Using console.profile, setInterval and function toString var devtools = function() {}; devtools.toString = function() { alert('NOPE!!') return '-' } setInterval(()=>{ console.profile(devtools) console.profileEnd(devtools) }, 1000) In safari, it doesn't works. Below chrome 89, i can't check whether it works.
The Chrome developer tools is really just a part of WebKit's WebCore library. So this question applies to Safari, Chrome, and any other WebCore consumers. If a solution exists, it'll be based off a difference in the DOM when the WebKit web inspector is open and when it's closed. Unfortunately, this is a kind of a chicken and egg problem because we can't use the inspector to observe the DOM when the inspector is closed. What you may be able to do is write a bit of JavaScript to dump the entire DOM tree. Then run it once when the inspector is open, and once when the inspector is closed. Any difference in the DOM is probably a side-effect of the web inspector, and we may be able to use it to test if the user is inspecting or not. This link is a good start for a DOM dumping script , but you'll want to dump the entire DOMWindow object, not just document. Update: Looks like there's a way to do this now. Check out Chrome Inspector Detector
There is a tricky way to check it for extensions with 'tabs' permission: chrome.tabs.query({url:'chrome-devtools://*/*'}, function(tabs){ if (tabs.length > 0){ //devtools is open } }); Also you can check if it open for your page: chrome.tabs.query({ url: 'chrome-devtools://*/*', title: '*example.com/your/page*' }, function(tabs){ ... })
I wrote a blog post about this: http://nepjua.org/check-if-browser-console-is-open/ It can detect whether it's docked or undocked function isConsoleOpen() { var startTime = new Date(); debugger; var endTime = new Date(); return endTime - startTime > 100; } $(function() { $(window).resize(function() { if(isConsoleOpen()) { alert("You're one sneaky dude, aren't you ?") } }); });
var div = document.createElement('div'); Object.defineProperty(div,'id',{get:function(){ document.title = 'xxxxxx' }}); setTimeout(()=>console.log(div),3000)
Muhammad Umer's approach worked for me, and I'm using React, so I decided to make a hooks solution: const useConsoleOpen = () => { const [consoleOpen, setConsoleOpen] = useState(true) useEffect(() => { var checkStatus; var element = new Image(); Object.defineProperty(element, "id", { get: function () { checkStatus = true; throw new Error("Dev tools checker"); }, }); requestAnimationFrame(function check() { checkStatus = false; console.dir(element); //Don't delete this line! setConsoleOpen(checkStatus) requestAnimationFrame(check); }); }, []); return consoleOpen } NOTE: When I was messing with it, it didn't work for the longest time and I couldn't figure out why. I had deleted console.dir(element); which is critical to how it works. I delete most non-descriptive console actions since they just take up space and aren't usually necessary to the function, so that was why it wasn't working for me. To use it: import React from 'react' const App = () => { const consoleOpen = useConsoleOpen() return ( <div className="App"> <h1>{"Console is " + (consoleOpen ? "Open" : "Closed")}</h1> </div> ); } I hope this helps anyone using React. If anyone wants to expand on this, I would like to be able stop the infinite loop at some point (since I don't use this in every component) and to find a way to keep the console clean.
Javascript Detect Developer Tools Console Opening Working from 2/2/2022 Chrome Version 97 (Developer Tools Undocked/Docked/Keyboard shortcuts) Edge Version 97 (Developer Tools Undocked/Docked/Keyboard shortcuts) FireFox Version 96.0.03 (Developer Tools Undocked/Docked/Keyboard shortcuts) Safari ? FireBug Detection (Developer Tools) // Prevent Right Click (Optional) document.addEventListener('contextmenu', function(event) { event.preventDefault(); }, true); // DevTools Opened Script function DevToolsOpened() { alert("Developer Tools Opened"); } // Detect DevTools (Chrome/Edge) // https://stackoverflow.com/a/67148898/9498503 (SeongJun) var devtools = function() {}; devtools.toString = function() { DevToolsOpened(); return '-'; } setInterval(()=>{ console.profile(devtools); console.profileEnd(devtools); if (console.clear) { console.clear(); } }, 1000); // Detect DevTools (FireFox) if (navigator.userAgent.toLowerCase().indexOf('firefox') > -1){ // Detect Resize (Chrome/Firefox/Edge Works) but (Triggers on Zoom In Chrome and Zoom Out FireFox) window.onresize = function() { if ((window.outerHeight - window.innerHeight) > 100 || (window.outerWidth - window.innerWidth) > 100) { DevToolsOpened(); } } } // Detect Fire Bug if (window.console && window.console.firebug || console.assert(1) === '_firebugIgnore') { DevToolsOpened(); }; // Detect Key Shortcuts // https://stackoverflow.com/a/65135979/9498503 (hlorand) window.addEventListener('keydown', function(e) { if ( // CMD + Alt + I (Chrome, Firefox, Safari) e.metaKey == true && e.altKey == true && e.keyCode == 73 || // CMD + Alt + J (Chrome) e.metaKey == true && e.altKey == true && e.keyCode == 74 || // CMD + Alt + C (Chrome) e.metaKey == true && e.altKey == true && e.keyCode == 67 || // CMD + Shift + C (Chrome) e.metaKey == true && e.shiftKey == true && e.keyCode == 67 || // Ctrl + Shift + I (Chrome, Firefox, Safari, Edge) e.ctrlKey == true && e.shiftKey == true && e.keyCode == 73 || // Ctrl + Shift + J (Chrome, Edge) e.ctrlKey == true && e.shiftKey == true && e.keyCode == 74 || // Ctrl + Shift + C (Chrome, Edge) e.ctrlKey == true && e.shiftKey == true && e.keyCode == 67 || // F12 (Chome, Firefox, Edge) e.keyCode == 123 || // CMD + Alt + U, Ctrl + U (View source: Chrome, Firefox, Safari, Edge) e.metaKey == true && e.altKey == true && e.keyCode == 85 || e.ctrlKey == true && e.keyCode == 85 ) { DevToolsOpened(); } });
Also you can try this: https://github.com/sindresorhus/devtools-detect // check if it's open console.log('is DevTools open?', window.devtools.open); // check it's orientation, null if not open console.log('and DevTools orientation?', window.devtools.orientation); // get notified when it's opened/closed or orientation changes window.addEventListener('devtoolschange', function (e) { console.log('is DevTools open?', e.detail.open); console.log('and DevTools orientation?', e.detail.orientation); });
If you are developers who are doing stuff during development. Check out this Chrome extension. It helps you detect when Chrome Devtoos is opened or closed. https://chrome.google.com/webstore/detail/devtools-status-detector/pmbbjdhohceladenbdjjoejcanjijoaa?authuser=1 This extension helps Javascript developers detect when Chrome Devtools is open or closed on current page. When Chrome Devtools closes/opens, the extension will raise a event named 'devtoolsStatusChanged' on window.document element. This is example code: function addEventListener(el, eventName, handler) { if (el.addEventListener) { el.addEventListener(eventName, handler); } else { el.attachEvent('on' + eventName, function() { handler.call(el); }); } } // Add an event listener. addEventListener(document, 'devtoolsStatusChanged', function(e) { if (e.detail === 'OPENED') { // Your code when Devtools opens } else { // Your code when Devtools Closed } });
Some answers here will stop working in Chrome 65. Here's a timing attack alternative that works pretty reliably in Chrome, and is much harder to mitigate than the toString() method. Unfortunately it's not that reliable in Firefox. addEventListener("load", () => { var baseline_measurements = []; var measurements = 20; var warmup_runs = 3; const status = document.documentElement.appendChild(document.createTextNode("DevTools are closed")); const junk = document.documentElement.insertBefore(document.createElement("div"), document.body); junk.style.display = "none"; const junk_filler = new Array(1000).join("junk"); const fill_junk = () => { var i = 10000; while (i--) { junk.appendChild(document.createTextNode(junk_filler)); } }; const measure = () => { if (measurements) { const baseline_start = performance.now(); fill_junk(); baseline_measurements.push(performance.now() - baseline_start); junk.textContent = ""; measurements--; setTimeout(measure, 0); } else { baseline_measurements = baseline_measurements.slice(warmup_runs); // exclude unoptimized runs const baseline = baseline_measurements.reduce((sum, el) => sum + el, 0) / baseline_measurements.length; setInterval(() => { const start = performance.now(); fill_junk(); const time = performance.now() - start; // in actual usage you would also check document.hasFocus() // as background tabs are throttled and get false positives status.data = "DevTools are " + (time > 1.77 * baseline ? "open" : "closed"); junk.textContent = ""; }, 1000); } }; setTimeout(measure, 300); });
As for Chrome/77.0.3865.75 a version of 2019 not works. toString invokes immediately without Inspector opening. const resultEl = document.getElementById('result') const detector = function () {} detector.toString = function () { resultEl.innerText = 'Triggered' } console.log('%c', detector) <div id="result">Not detected</div>
use this package isDevToolsOpened() function from the package dev-tools-monitor which works as expected in all browsers except for firefox.
Force a colorized welcome message, each time the console is opened. // Force a colorized welcome message // each time the console is opened. (() => { w = new Function() w.toString = () => { (!this.z) ? console.log("%cWelcome to the console\n %cMaster password:\n %c window.password = ' ... ':", "color: white; font-size: 20px; background-color: blue", "color: white; font-size: 16px; background-color: red;margin 20px 0", "background: #222; color: #bada55") : this.z = true } console.log('%c', w) })()
You can catch the event of opening the dev. tools by adding event listeners to the keyboard shortcuts with which it opens. This is not a "hack" and it works 100% of the time. The only case it won't catch is when the user opens it manually with mouse. So it is a "partial solution" perhaps it is useful for somebody. <script> function devToolsOpened(e){ alert("devtools opened"); // uncomment to prevent opening dev.tools: // e.preventDefault(); } window.addEventListener('keydown', function(e) { if ( // CMD + Alt + I (Chrome, Firefox, Safari) e.metaKey == true && e.altKey == true && e.keyCode == 73 || // CMD + Alt + J (Chrome) e.metaKey == true && e.altKey == true && e.keyCode == 74 || // CMD + Alt + C (Chrome) e.metaKey == true && e.altKey == true && e.keyCode == 67 || // CMD + Shift + C (Chrome) e.metaKey == true && e.shiftKey == true && e.keyCode == 67 || // Ctrl + Shift + I (Chrome, Firefox, Safari, Edge) e.ctrlKey == true && e.shiftKey == true && e.keyCode == 73 || // Ctrl + Shift + J (Chrome, Edge) e.ctrlKey == true && e.shiftKey == true && e.keyCode == 74 || // Ctrl + Shift + C (Chrome, Edge) e.ctrlKey == true && e.shiftKey == true && e.keyCode == 67 || // F12 (Chome, Firefox, Edge) e.keyCode == 123 || // CMD + Alt + U, Ctrl + U (View source: Chrome, Firefox, Safari, Edge) e.metaKey == true && e.altKey == true && e.keyCode == 85 || e.ctrlKey == true && e.keyCode == 85 ){ devToolsOpened(e); } }); </script> Keyboard shortcuts to open Developer Tools: Chrome: https://developers.google.com/web/tools/chrome-devtools/shortcuts Firefox: https://developer.mozilla.org/hu/docs/Tools Safari: https://developer.apple.com/library/archive/documentation/AppleApplications/Conceptual/Safari_Developer_Guide/KeyboardShortcuts/KeyboardShortcuts.html Edge: https://learn.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/shortcuts
Timing solution (works for docked and undocked) It is a bit intrusive but not as much as the debugger trap var opened = false; var lastTime = Date.now(); const interval = 50; const threshold = 30; setInterval(() => { let delta = Date.now() - lastTime; if (delta > interval + threshold) { document.title = "P3nis"; opened = true; } lastTime = Date.now(); if (!opened) { debugger; } }, interval)
When a browser's DevTools is open, breakpoints marked by 'debugger;' will be attached as long as you don't deactivate breakpoints. So here is the code to check if debugger is enabled: let workerUrl = 'data:application/javascript;base64,' + btoa(` self.addEventListener('message', (e) => { if(e.data==='hello'){ self.postMessage('hello'); } debugger; self.postMessage(''); }); `); function checkIfDebuggerEnabled() { return new Promise((resolve) => { let fulfilled = false; let worker = new Worker(workerUrl); worker.onmessage = (e) => { let data = e.data; if (data === 'hello') { setTimeout(() => { if (!fulfilled) { resolve(true); worker.terminate(); } }, 1); } else { fulfilled = true; resolve(false); worker.terminate(); } }; worker.postMessage('hello'); }); } checkIfDebuggerEnabled().then((result) => { if (result) { alert('browser DevTools is open'); }else{ alert('browser DevTools is not open, unless you have deactivated breakpoints'); } }); Note: if CSP is used then you need either to add worker-src 'unsafe-inline' to CSP policy or to move worker source code above to a CSP-allowed resource and change workerUrl to that resource.
Best way to have Debug-Mode on/off feature is to set a flag 'debugMode'='off' in localStorage by default - localStorage.setItem('debugMode', 'off'); Then, change it in Local Storage of browser manually to 'on' while development - Then use below condition in code to do differrent action if it's 'on' - if(localStorage.getItem('debugMode') === 'on'){ //do something 1 }else { //do something 2 }