Averigua si la consola Chrome está abierta

141

Estoy usando este pequeño script para averiguar si Firebug está abierto:

if (window.console && window.console.firebug) {
    //is open
};

Y funciona bien. Ahora estaba buscando durante media hora para encontrar una manera de detectar si la consola de desarrollador web incorporada de Google Chrome está abierta, pero no pude encontrar ninguna pista.

Esta:

if (window.console && window.console.chrome) {
    //is open
};

no funciona

EDITAR:

Por lo tanto, parece que no es posible detectar si la consola Chrome está abierta. Pero hay un " hack " que funciona, con algunos inconvenientes:

  • no funcionará cuando la consola esté desacoplada
  • no funcionará cuando la consola esté abierta al cargar la página

Por lo tanto, voy a elegir la respuesta de Unsigned por ahora, pero si a alguien se le ocurre una idea brillante, ¡puede responder y cambiar la respuesta seleccionada! ¡Gracias!

r0skar
fuente
La solución en la respuesta parece funcionar, sin embargo, solo si la consola está acoplada. Además, no funciona si la consola ya está abierta al cargar la página, mientras que el script Firebug no tiene estos problemas y parece que siempre funciona. ¡Pero puedo vivir con eso por ahora! Muchas gracias @pimvdb !! Mantendré la pregunta abierta de todos modos para encontrar una forma similar al script Firebug, que siempre funciona.
r0skar
He estado intentando cosas como arrojar un error y ver si .messagese recupera (lo que sucede cuando el depurador está abierto porque ves el mensaje), pero desafortunadamente esto también sucede cuando el depurador no está abierto. Me gustaría saber un truco para esto si es que existe ...
pimvdb
44
@Spudley No es relevante para la pregunta de por qué lo necesito y no quiero comenzar a explicarlo. Sé que no hay forma de evitar que alguien1 depure, pero eso no es lo que estoy tratando de hacer. Solo estoy tratando de encontrar una manera de saber si la consola está abierta o no. Eso es todo :)
r0skar
1
El método JFYI console.profiles se eliminó de la API de consola recientemente src.chromium.org/viewvc/blink?view=revision&revision=151136
loislo

Respuestas:

97

requestAnimationFrame (finales de 2019)

Dejando estas respuestas anteriores aquí para el contexto histórico. Actualmente, el enfoque de Muhammad Umer funciona en Chrome 78, con la ventaja adicional de detectar tanto eventos cercanos como abiertos.

función toString (2019)

Crédito para Overcl9ck comentario 's en esta respuesta. Reemplazar la expresión regular /./con un objeto de función vacío todavía funciona.

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)

Dado que el autor de la pregunta original ya no parece estar presente y esta sigue siendo la respuesta aceptada, agrega esta solución para la visibilidad. El crédito va a Antonin Hildebrand 's comentario sobre zswang ' s respuesta . Esta solución aprovecha el hecho de que toString()no se llama a los objetos registrados a menos que la consola esté abierta.

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)

Actualización: console.profiles se ha eliminado de Chrome. Esta solución ya no funciona.

Gracias a Paul Irish por señalar esta solución de Discover DevTools , utilizando el generador de perfiles:

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)

Esta otra opción puede detectar la apertura del inspector acoplado , después de cargar la página, pero no podrá detectar un inspector desacoplado, o si el inspector ya estaba abierto en la carga de la página. También hay potencial para falsos positivos.

window.onresize = function() {
  if ((window.outerHeight - window.innerHeight) > 100) {
    alert('Docked inspector was opened');
  }
}

No firmado
fuente
1
Obteniendo TypeError: no se puede leer la propiedad 'longitud' de undefined en isInspectOpen ()
sandeep
2
Hay una nueva mejor manera (créditos: @zswang): stackoverflow.com/questions/7798748/…
Vicky Chijwani
3
la solución de 'toString (2017)' no funciona en Chrome
Richard Chan
2
toString parece haber sido reparado en cromo. Editar. En realidad, funciona si usa function() {}una expresión regular en lugar de una expresión regular
Overcl9ck
1
@ Overcl9ck su solución estaba funcionando hasta la última actualización de Chrome 77. ¿Puede indicarnos la dirección correcta para una solución alternativa?
Agustin Haller
118

Chrome 65+ (2018)

r = /./
r.toString = function () {
    document.title = '1'
}
console.log('%c', r);

demostración: https://jsbin.com/cecuzeb/edit?output (Actualización en 2018-03-16)

paquete: https://github.com/zswang/jdetects


Al imprimir "Element", las herramientas de desarrollador de Chrome obtendrán su id.

var checkStatus;

var element = document.createElement('any');
element.__defineGetter__('id', function() {
    checkStatus = 'on';
});

setInterval(function() {
    checkStatus = 'off';
    console.log(element);
    console.clear();
}, 1000);

Otra versión (de comentarios)

var element = new Image();
Object.defineProperty(element, 'id', {
  get: function () {
    /* TODO */
    alert('囧');
  }
});
console.log('%cHello', element);

Imprima una variable regular:

var r = /./;
r.toString = function() {
  document.title = 'on';
};
console.log(r);
zswang
fuente
3
Gran respuesta. Una cosa para agregar ... MDN dice que __defineGetter__está en desuso, así que cambié a Object.defineProperty(element, 'id', {get:function() {checkStatus='on';}});... aún trabajando.
denikov
55
Además, la consola 'leerá' el elemento tan pronto como se abra la consola, por lo que podría imprimir una vez y esperar a que se ejecute la función en el getter en lugar de configurar unsetInterval
xpy
8
Basado en este descubrimiento pude encontrar un método menos intrusivo. DevTools llama a toString () sobre funciones cuando las imprime en la consola. Por lo tanto, se puede imprimir un objeto de función personalizada con el método toString () para reemplazar la cadena vacía. Además, puede usar la cadena de formato de consola% c y establecer el color: transparente para asegurarse de que el texto potencialmente impreso se imprima como invisible. Usé
Antonin Hildebrand
3
Año 2017 aquí. Chrome todavía escribe cosas en la consola sin que la abras. Y tu truco ya no funciona.
vothaison
2
Probado en firefox no funciona con el elemento de inspección (Q) y el elemento de inspección con firebug
Asif Ashraf
27

Hack muy confiable

Básicamente establezca un getter en la propiedad e inicie sesión en la consola. Aparentemente, solo se accede a la cosa cuando la consola está abierta.

https://jsfiddle.net/gcdfs3oo/44/

var checkStatus;

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);
  document.querySelector('#devtool-status').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>

Muhammad Umer
fuente
Chrome versión 79 ✅
Legends
44
¿Qué es la throw new Error("Dev tools checker");de? Porque funciona sin eso.
Leyendas
esto parece enviar spam a la consola (cuando está abierta)? que supongo que comenzará a comer cantidades significativas de memoria después de unos días :)
pythonator
24

He creado devtools-detectan que detecta cuando DevTools está abierto:

console.log('is DevTools open?', window.devtools.open);

También puedes escuchar un evento:

window.addEventListener('devtoolschange', function (e) {
    console.log('is DevTools open?', e.detail.open);
});

No funciona cuando DevTools está desacoplado. Sin embargo, funciona con Chrome / Safari / Firefox DevTools y Firebug.

Sindre Sorhus
fuente
@barbushin Creo que su devtool abierto está acoplado, no puede detectar una ventana separada.
Mithril
15

Encontré una manera de saber si Chrome Console está abierta o no. Todavía es un truco, pero es mucho más preciso y funcionará si la consola está desacoplada o no.

Básicamente, ejecutar este código con la consola cerrada tarda aproximadamente ~ 100 microsegundos y mientras la consola está abierta, tarda aproximadamente el doble ~ 200 microsegundos.

console.log(1);
console.clear();

(1 milisegundo = 1000 microsegundos)

He escrito más sobre esto aquí .

La demo está aquí .


Actualizar:

@zswang ha encontrado la mejor solución actual - mira su respuesta

guya
fuente
1
Es una solución muy incorrecta. Google -> "Riesgo de carrera". ¿Computadora más lenta o más rápida y ...?
18C
1
"Riesgo racial" no está relacionado aquí. Siempre hay una relativa lentitud cuando se abre la consola.
guya
1
Lentitud relativa pero no siempre 100 o 200 ms. Por lo tanto, el peligro racial. Por cierto. Si jugará un juego al mismo tiempo, esta "solución" arrojará un resultado falso positivo.
18C
8

Si su objetivo es bloquear las herramientas del desarrollador, intente esto (encontré una versión más complicada en un lugar donde el código JS estaba ofuscado, es muy molesto):

setTimeout(function() {while (true) {eval("debugger");}}, 0);
Robert Moore
fuente
El usuario puede, en Chrome, deshabilitar la escucha del depurador.
Jack Giffin
3

Hay una forma complicada de verificar si hay extensiones con permiso de 'pestañas':

chrome.tabs.query({url:'chrome-devtools://*/*'}, function(tabs){
    if (tabs.length > 0){
        //devtools is open
    }
});

También puede verificar si está abierto para su página:

chrome.tabs.query({
    url: 'chrome-devtools://*/*',
    title: '*example.com/your/page*'
}, function(tabs){ ... })
norlin
fuente
3

Escribí una publicación de blog sobre esto: http://nepjua.org/check-if-browser-console-is-open/

Puede detectar si está acoplado o desacoplado

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
fuente
3
Eso es bueno, pero va a retrasar la página y no se mostrará ningún mensaje hasta que el usuario haga clic en el botón de reanudar. Será muy intrusivo para el usuario.
guya
2
Siguiente solución "Peligro de carrera". Muy mal. Por cierto. El comando "depurador" se puede deshabilitar.
18C
3
var div = document.createElement('div');
Object.defineProperty(div,'id',{get:function(){
    document.title = 'xxxxxx'
}});

setTimeout(()=>console.log(div),3000)
Huiting Chen
fuente
No funcionó. Y el enlace a test onlineno funcionó.
Samuel
2

Las herramientas para desarrolladores de Chrome son realmente solo una parte de la biblioteca WebCore de WebKit. Entonces, esta pregunta se aplica a Safari, Chrome y cualquier otro consumidor de WebCore.

Si existe una solución, se basará en una diferencia en el DOM cuando el inspector web de WebKit esté abierto y cuando esté cerrado. Desafortunadamente, este es un tipo de problema de huevo y gallina porque no podemos usar el inspector para observar el DOM cuando el inspector está cerrado.

Lo que puede hacer es escribir un poco de JavaScript para volcar todo el árbol DOM. Luego ejecútelo una vez cuando el inspector esté abierto y una vez cuando el inspector esté cerrado. Cualquier diferencia en el DOM es probablemente un efecto secundario del inspector web, y podemos usarlo para probar si el usuario está inspeccionando o no.

Este enlace es un buen comienzo para un script de volcado DOM, pero querrá volcar todo el DOMWindowobjeto, no solo document.

Actualizar:

Parece que hay una manera de hacer esto ahora. Echa un vistazo a Chrome Inspector Detector

pepsi
fuente
Chrome Inspector Detector ya no funciona para Google Chrome como lo menciona el desarrollador
Angelo
1

También puedes probar esto: 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);
});
Vladimir Ishenko
fuente
1
No funciona bien Si un usuario está en un dispositivo móvil, gira su dispositivo 90 grados y la pantalla cambiará de tamaño.
Jack Giffin
funciona en cromo y ff no es decir o borde a partir del 4/4/2019
SolidSnake
0

Si son desarrolladores que están haciendo cosas durante el desarrollo. Mira esta extensión de Chrome. Te ayuda a detectar cuándo Chrome Devtoos está abierto o cerrado.

https://chrome.google.com/webstore/detail/devtools-status-detector/pmbbjdhohceladenbdjjoejcanjijoaa?authuser=1

Esta extensión ayuda a los desarrolladores de Javascript a detectar cuándo Chrome Devtools está abierto o cerrado en la página actual. Cuando Chrome Devtools se cierra / abre, la extensión generará un evento llamado 'devtoolsStatusChanged' en el elemento window.document.

Este es el código de ejemplo:

 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
fuente
0

Algunas respuestas aquí dejarán de funcionar en Chrome 65. Aquí hay una alternativa de ataque de sincronización que funciona de manera bastante confiable en Chrome y es mucho más difícil de mitigar que el toString()método. Lamentablemente, no es tan confiable en 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 Gray
fuente
0

En cuanto a Chrome / 77.0.3865.75, una versión de 2019 no funciona. toString invoca inmediatamente sin la apertura del Inspector.

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
fuente
0

El enfoque de Muhammad Umer funcionó para mí, y estoy usando React, así que decidí hacer una solución de ganchos:

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
}

NOTA: Cuando estaba jugando con eso, no funcionó durante mucho tiempo y no podía entender por qué. Había eliminado lo console.dir(element);que es crítico para cómo funciona. Elimino la mayoría de las acciones de consola no descriptivas, ya que solo ocupan espacio y, por lo general, no son necesarias para la función, por eso no me funcionó.

Para usarlo:

import React from 'react'

const App = () => {
  const consoleOpen = useConsoleOpen()

  return (
    <div className="App">
      <h1>{"Console is " + (consoleOpen ? "Open" : "Closed")}</h1>
    </div>
  );
}

Espero que esto ayude a cualquiera que use React. Si alguien quiere ampliar esto, me gustaría poder detener el bucle infinito en algún momento (ya que no lo uso en todos los componentes) y encontrar una manera de mantener limpia la consola.

Luke Redmore
fuente