183

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!

Community
  • 1
  • 1
r0skar
  • 7,687
  • 13
  • 49
  • 68
  • possible duplicate of [How to detect Chrome Inspect Element is running or not?](http://stackoverflow.com/questions/7527442/how-to-detect-chrome-inspect-element-is-running-or-not) – pimvdb Oct 17 '11 at 20:09
  • The solution in the answer seems to work, however only if the console is docked. Also it doesn't work if the console is already open on page load, while the Firebug script does not have this problems and seems to always work. But I can live with that for now! Thanks a lot @pimvdb!! I will keep the question open anyways to maybe find a way similar to the Firebug script, that always works. – r0skar Oct 17 '11 at 20:16
  • I've been trying things like throwing an error and see whether `.message` is fetched (which happens when the debugger is open because you see the message), but unfortunately this also happens when the debugger is not opened. I'd like to know a hack for this if it exists... – pimvdb Oct 18 '11 at 15:07
  • The question is why do you need to do this? If you're trying to prevent debugging, there are other debugging tools which can be used instead. – Spudley Oct 18 '11 at 15:07
  • 4
    @Spudley It is not relevant to the question why I need it and I dont want to start explaining. I do know there is no way to prevent some1 from debugging, but thats not what I am trying to do. I am just trying to figure out a way to know if the console is open or not. Thats all :) – r0skar Oct 18 '11 at 15:24
  • 1
    JFYI console.profiles method was removed from console API recently http://src.chromium.org/viewvc/blink?view=revision&revision=151136 – loislo May 29 '13 at 19:18

24 Answers24

130

requestAnimationFrame (Late 2019)

Leaving these previous answers here for historical context. 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');
  }
}
KTibow
  • 301
  • 4
  • 15
Unsigned
  • 9,263
  • 4
  • 45
  • 68
  • To Unsigned: are you absolutely sure there is no way to detect it? but what about detecting it when its docked BUT open on page load(the "hacky" way doesnt work there too)? – r0skar Oct 18 '11 at 15:27
  • @Andrej: You are correct, I was actually just testing that myself before posting it. If the inspector is *already* open on page load, that script will not be able to detect it. You may also get false positives when working with certain framesets. – Unsigned Oct 18 '11 at 15:28
  • @Unsigned: Alright, I will keep the question open just in case some1 comes up with something amazingly brilliant :) Otherwise I am gonna mark your answer tomorrow. I hope thats fine with you :) – r0skar Oct 18 '11 at 15:41
  • You can make this technique slightly less obtrusive by using a collapsed console group to hide the messages that are generated by running the profiler. See https://github.com/adamschwartz/chrome-inspector-detector – Adam Apr 12 '13 at 03:50
  • JFYI console.profiles method was removed from console API recently src.chromium.org/viewvc/blink?view=revision&revision=151136 – loislo May 29 '13 at 19:19
  • This will cease to work soon in Chrome: https://codereview.chromium.org/15816002 (Sorry, y'all) – Paul Irish Jun 04 '13 at 19:22
  • 2
    Getting TypeError: Cannot read property 'length' of undefined in isInspectOpen() – sandeep Feb 16 '14 at 16:49
  • FYI, `100` is an unknown value of the `actual browser window's height` - `the document window's height` as `outerHeight` is the height of the whole browser window. So, in chrome's case, `100` is the header's height. – Matthias Jan 29 '16 at 01:03
  • This not correctly, when i resize browser (not open developer tools) alert still show. – Nguyễn Huy May 06 '16 at 09:37
  • @NguyễnHuy "There is also some potential for false positives." – Unsigned May 06 '16 at 17:27
  • 2
    There's a _new_ new best way (credits: @zswang): http://stackoverflow.com/questions/7798748/find-out-whether-chrome-console-is-open/30638226#30638226 – Vicky Chijwani May 10 '16 at 13:02
  • THERE IS A WAY TO DETECT NO MATTER WHAT!! You need to call the same function for `window.resize` (in the *update* code in this answer) when the page loads. – Cameron Jul 24 '17 at 02:46
  • FWIW you should put the date next to your update edit title. Hard to know which order updates are in at first glance. – ScottN Jan 19 '18 at 20:08
  • @ScottN I've added at least the year for all three answers. Hope that helps make the ordering more obvious. – Unsigned Jan 19 '18 at 21:50
  • 3
    the solution of 'toString (2017)' does not work in chrome – Richard Chan Mar 01 '18 at 03:42
  • 2
    toString seem to have been fixed in chrome. Edit. Actually it works if you use a `function() {}` instead of a regex – Overcl9ck Jun 13 '19 at 13:49
  • 1
    @Overcl9ck your solution was working until the latest Chrome 77 update. Can you point us in the right direction for a workaround? – Agustin Haller Sep 18 '19 at 23:11
  • 2
    Confirmed with Chrome v80.0.3987.149 - still not working. – BananaAcid Apr 09 '20 at 22:04
129

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);
Community
  • 1
  • 1
zswang
  • 2,254
  • 3
  • 15
  • 13
  • 4
    Great answer. One thing to add...MDN says `__defineGetter__` is deprecated so I changed to `Object.defineProperty(element, 'id', {get:function() {checkStatus='on';}});`...still working. – denikov Mar 07 '16 at 02:27
  • You can also avoid clearing the console every second by going throwing an error in the setter. Chrome will collapse like errors by default. https://jsfiddle.net/gcdfs3oo/ – endy Mar 22 '16 at 14:21
  • 5
    Also the console will 'read' the element as soon as the console opens, so you could just print once and just wait for the function in the getter to execute instead of setting an `setInterval` – xpy May 17 '16 at 06:39
  • 9
    Based on this discovery I was able to find less-intrusive method. DevTools calls toString() on functions when printing them to console. So one can print a custom function object with toString() method override returning empty string. Additionally you could use console formatting string %c and set color:transparent to make sure potentially printed text prints as invisible. I used this technique here: https://github.com/binaryage/cljs-devtools/blob/2e0615e7e037945db8ff39581de6cd367d9388d4/src/lib/devtools/util.cljs#L108 – Antonin Hildebrand Jun 08 '16 at 14:21
  • 4
    Year 2017 here. Chrome still writes things to console without you opening it. And your hack don't work anymore. – vothaison Jul 04 '17 at 04:34
  • Here is another one where the dev console doesn't get spammed (if default logging is set) and doesn't clear the timeout: [https://jsfiddle.net/vic10us/w5tjzvcw/](https://jsfiddle.net/vic10us/w5tjzvcw/) – Keith Hill Sep 28 '17 at 18:29
  • 2
    Tested on firefox doesn't work with Inspection Element(Q) and Inspect Element with firebug – Asif Ashraf Oct 17 '17 at 16:28
  • the first example in Chromium 63 still work, but the toString with regex or function don't – jcubic Jan 06 '18 at 16:35
  • 1
    Chrome canary now prevents the first method from working (https://github.com/zswang/jdetects/issues/3) – Sam Denty Feb 12 '18 at 02:29
  • For anyone looking to bypass this on annoying websites, just debug a script, and before it loads run this in dev console: `Image = null;` – dustytrash Nov 08 '20 at 02:04
49

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>
Legends
  • 19,109
  • 11
  • 87
  • 115
Muhammad Umer
  • 15,996
  • 17
  • 81
  • 153
  • Chrome version 79 ✅ – Legends Dec 15 '19 at 21:29
  • 6
    What's the `throw new Error("Dev tools checker");` for? Because it works without it. – Legends Dec 15 '19 at 21:35
  • 1
    this appears to spam the console (when open)? which I assume will start to eat significant amounts of memory after a few days :) – pythonator Jul 06 '20 at 14:10
  • 1
    Ingenious! This method can be subverted with something like `console.log = function() {}` and `console.dir = function() {}`. – Nathan Goings Sep 02 '20 at 17:41
  • Is it possible to redirect page if Inspect Element Opens. Please tell if Possible. Thank You – Himanshu Jain Oct 06 '20 at 05:38
  • 7
    Chrome Canary 89.0.4373.0 no longer works ❎ – Dickeylth Dec 31 '20 at 02:16
  • would this mean chrome will intentionally patch this in the future or is this just something broken with canary – Directory Jan 05 '21 at 22:31
  • 1
    @Legends if you try to access `element.id` yourself in your code it will throw an error so that you know you're using this wrong. `console.log(element.id)` will not work because you're accessing `id` yourself and the goal is get the console to access that property. `console.dir` will automatically access all properties of the argument it was supplied and it will suppress/ignore that error. That's why this is a clever hack because it's forcing the console to do the property access. Now if we could only figure out a way to not spam the console – Francisc0 Feb 18 '21 at 18:18
  • 4
    This no longer works in chrome 90 (stable) – eoleary May 20 '21 at 15:24
  • Doesn't work in FF 90 either. Horrible performance while using this too, only spews out content into the console – Zoe stands with Ukraine Aug 06 '21 at 20:49
27

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.

Sindre Sorhus
  • 62,461
  • 37
  • 161
  • 226
19

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 weather 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.


Update:

@zswang has found the current best solution - check out his answer

guya
  • 4,733
  • 34
  • 28
  • 1
    It is very wrong solution. Google it -> "Race Hazard". Slower or faster computer and...? – 18C Oct 27 '17 at 12:18
  • 2
    "Race Hazard" is not related here. There is always a relative slowness when the console is opened. – guya Oct 27 '17 at 22:33
  • 1
    Relative slowness but not always 100 or 200ms. Thus Race Hazard. Btw. If you will play a game in the same time, this "solution" will return false positive result. – 18C Oct 28 '17 at 21:19
8

If your goal is to jam the developer tools, try this (I found a more complicated version of it at a place where JS code was obfuscated, it's very annoying):

setTimeout(function() {while (true) {eval("debugger");}}, 0);
Robert Moore
  • 1,831
  • 1
  • 18
  • 40
  • 2
    The user can, in Chrome, disable listening to the debugger. – Jack G Nov 11 '18 at 14:42
  • @JackGiffin, Until recently there was a weird issue in Chrome Deactivating breakpoints didn't work 100%. It's fixed now, but at the time this post worked. – Nathan Goings Sep 02 '20 at 17:22
8

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.

SeongJun
  • 81
  • 1
  • 1
5

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 ?")
    }
  });
});
nepjua
  • 538
  • 6
  • 17
  • 3
    That's nice, but, it'll stale the page and no message will be shown until the user will click the resume button. It'll be highly intrusive for the user. – guya Mar 09 '15 at 11:32
  • 4
    Next "Race Hazard" solution. Very wrong. BTW. "debugger" command can be disabled. – 18C Oct 27 '17 at 12:20
  • I've created a similar solution https://stackoverflow.com/a/68494829/11107541 that doesn't block the main thread. Limitations are listed in the repo readme. Also, I noticed that Chrome 91 (and maybe others) "forget" the setting of "disable all breakpoints" upon closing devtools, which can be good or bad depending on what you want, but I think to most people here it will be good. – David Fong Aug 18 '21 at 02:08
4

Here's a solution that I've got working on Chrome and Firefox* (today is 2021 July 22nd): https://github.com/david-fong/detect-devtools-via-debugger-heartstop.

I'll test it on Safari later.

Copied from the readme:

It opens a web worker with a polling loop that sends pulses to the main thread. Each pulse is two messages with a debugger statement in between them, which will create an abnormal delay between enclosing messages when devtools are opened on any browser that implements debugging workers and enables debugging always-if-and-only-if the devtools are opened. It does not block the main thread.

On FireFox, it only works when the active devtools tab is the debugger.

More details about pros and cons and who should and shouldn't use it are in the readme.

David Fong
  • 96
  • 1
  • 4
3

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){ ... })
norlin
  • 1,155
  • 10
  • 24
3
var div = document.createElement('div');
Object.defineProperty(div,'id',{get:function(){
    document.title = 'xxxxxx'
}});

setTimeout(()=>console.log(div),3000)

huiting Chen
  • 189
  • 2
  • 7
3

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.

Luke Redmore
  • 441
  • 3
  • 9
3

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

pepsi
  • 6,615
  • 6
  • 41
  • 72
  • 1
    Chrome Inspector Detector no longer works for google chrome as mentioned by the developer – Angelo Sep 14 '15 at 01:56
  • not only what @Angelo wrote, but also, you're partially right observing different browsers, yet saying that "we can't use the inspector to observe the DOM when the inspector is closed" => Well you can, you can send an XMLHttpRequest to a webservice that would load a boolean detecting if inspector open/closed, and also closed would send the response, independent of your client console being unattainable. – clusterBuddy Jul 01 '21 at 02:52
2

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();
    }
});
Natro90
  • 246
  • 2
  • 6
2
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

molnarg
  • 2,565
  • 1
  • 16
  • 19
1

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);
});
vovchisko
  • 1,682
  • 1
  • 19
  • 24
  • 1
    Does not work well. If a user is on a mobile device, then they turn their device 90 degrees, then the screen will resize. – Jack G Nov 11 '18 at 14:45
  • works on chrome and ff not ie or edge as of 4/5/2019 – Desolator Apr 05 '19 at 23:49
  • Cute, but all that code does is check the window size and the inside HTML size (to see if the side of the page has anything in there) - while most of the time "devtools" lives on the side of the page, it's not the only thing that does (e.g. false positives), and it doesn't always live there (e.g. false negatives): this code is not actually detecting devtools at all. – cnd Aug 31 '21 at 05:05
1

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 -

enter image description here

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
}

0

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
    }
});
vothaison
  • 1,536
  • 13
  • 14
0

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);

});
Eli Grey
  • 34,148
  • 13
  • 72
  • 93
0

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>
korzhyk
  • 166
  • 1
  • 8
0

use this package isDevToolsOpened() function from the package dev-tools-monitor which works as expected in all browsers except for firefox.

0

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:

hlorand
  • 712
  • 6
  • 7
  • There's an infinite amount of ways to open dev tools. For example, context menu. Disabling it will destroy accessibility. Another one is (for Chrome at least) the 3 dots on the upper right corner. If you click it, then click more tools, then you can also open developer tools. – code May 06 '21 at 01:56
  • @code There are 3 ways to open devtools: With keyboard shortcuts, and with mouse: either with right click or with the browser menu you wrote. This code catches every keyboard shortcut opening method in major browsers - and does not disables it (it is only a commented out *example* of what you can do with it). There is no need to downwote my comment. This partial solution is useful for somebody, because it works every time - not like other hacky solutions. – hlorand May 27 '21 at 00:17
  • I did not downvote your solution. My guess is because it doesn't exactly answer the question. – code May 27 '21 at 01:17
0

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)
})()
NVRM
  • 8,789
  • 1
  • 69
  • 80
0

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)
Viktor Veselý
  • 243
  • 3
  • 9