# disable-devtool blocks the shortcuts, the right-click and the browser menu, then admits it cannot always work

> theajack/disable-devtool is a small TypeScript library that prevents developer tools from being opened in a page, using multiple detection probes rather than one trick. Its most interesting documentation is the troubleshooting section, which walks through two failure modes and ends by asking for a browser version and asking readers to file an issue, because there is no universal way to locate the bug.

**theajack/disable-devtool** — Disable web developer tools from the f12 button, right-click and browser menu

- Repository: https://github.com/theajack/disable-devtool
- Website: https://theajack.github.io/disable-devtool/
- Stars: 3,559 · Forks: 308
- Language: TypeScript
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/theajack-disable-devtool

## Fourteen features, and two are about pretending to be elsewhere

The feature list has fourteen entries and reads as a checklist of every way developer tools can be reached. The first three are the obvious ones: a configurable right-click block, the shortcut keys including the function key and a modifier combination, and recognition of tools opened from the browser's own menu, which closes the current page instead. Then come the parts that make it more than a key handler. It can be suspended and resumed. It can be told to ignore certain attributes so you can leave probing on in development. It can be configured to apply to every parent page inside a frame. It can also detect two specific in-page debugging consoles by name, and, most unusually, it identifies whether the real device is a mobile terminal and, if so, tells the page to pretend to be one so the probes can take a cheaper path.

```bash
npm i disable-devtool
```

```js
import DisableDevtool from 'disable-devtool';

DisableDevtool();
```

## The bypass is two parameters encrypted with two hashes

The fourth feature is the one that tells you what kind of project this is: developers can bypass the disable, and the URL parameters carrying that bypass are encrypted with two separate hashes. The configuration exposes both halves. One option takes the hash value that permits a bypass and is disabled by default. The other names the URL parameter that carries it, defaulting to a short mnemonic. So the protection is designed to be lifted by someone who knows two values, which means it stops a user who wants to look at your page and stops nobody who is prepared to read the source. The readme is explicit that the goal is preventing code being ported out through the tools, which is a commercial concern rather than a security one.

## The call returns whether it started, and why not

The one genuinely good piece of API design here is the return value, and it is a small interface with two fields. The first is a boolean saying whether the thing is enabled normally. The second is a string giving the reason it was not properly enabled. That combination matters because the library's whole failure mode is silent: a probe that does not fire leaves a page where the developer tools open and nothing happens, which is indistinguishable from the library working correctly. Returning a reason lets a caller log it, surface it in development, or refuse to start an application whose protections are not actually in place. The recommended installation route is the package manager one, with the stated reason that a script tag can be intercepted separately by an agent and therefore never executed. That is a small but telling piece of reasoning: the author considers a blocked script tag a feature, because a tool that is prevented from running is a tool that cannot be inspected at all.

## The troubleshooting section admits there is no universal answer

The readme contains a collapsible section on false triggers, and it is the most honest part of the documentation. It opens by saying that because there are many devices, browsers and operating environments, some scenarios where the library is incompatible are inevitable, and that the section exists so developers can narrow the problem themselves before filing an issue. It then splits into two cases. The first is a probe firing when it should not, where a callback reports which probe was triggered, with a note that if you are worried about blocking the page you can use a console warning instead of a dialog. The second is the harder one: the tools are open, the page does not close, and no probe fires. The advice is to print whether the library is running, and if it says yes, this is an incompatibility, and there is currently no universal way to locate it.

## An issue template that asks for the environment

What follows that admission is the request: submit an issue, as detailed as possible, with the browser version, the device model and version, and the operating environment, preferably with a screenshot or a demo address. That list is effectively the compatibility matrix the library has no way to declare, and asking for it rather than publishing one is an honest reflection of a mechanism that depends on observable browser behaviour. It also explains why the search terms for this project include bypasses, workarounds and automation tools: a detection heuristic that runs in the page is something a page under automated control can simply not trigger. Nothing in the documentation claims the block is unbreakable, and the existence of a configurable bypass in the configuration surface says so plainly.

## Script tags configure themselves through an attribute

There are two ways in, and the second needs no JavaScript of your own. With a package you import the module and call the exported function. With a content delivery network you add a script tag that carries an attribute naming the behaviour, and the presence of that attribute is what makes the library activate itself on load. That is why the configuration surface works differently between the two routes: with a module you pass an options object to the function, and with a tag you express the same intent through markup. Version pinning is offered explicitly, with two forms, one naming an exact version and one asking for the latest published version. So the tag route is the one to use for a static page, and the package route is the one to use when you need to read the return value. Both routes can be configured, but the two examples in the readme make the difference clear: the module route passes an options object directly, while the tag route expresses the same intent in markup and then, if you need a callback, loads a second script that calls the global. That second step is the rough edge of the tag approach, since the library has to be loaded twice to be both active and observable.

## The manifest is ahead of its own tags

The version numbers do not line up. The manifest reads a patch version whose last two digits are later than the newest tag in the release history, and that tag itself is from December 2023, while the recorded last commit is from May 2026. Two of the older tags were cut on the same afternoon about eleven hours apart, which is the signature of a fix pushed quickly rather than a planned release. The manifest itself is a small one and tells you how the build works. Three separate fields, for the package entry, for one CDN and for the other, all name the same minified file, so both content delivery networks resolve to one artefact without a second path to keep in sync. A build script, a documentation build script, a CDN purge script and a release script are each a single file, and the compiled output directory is committed at the repository root.
```js
DisableDevtool({
    ondevtoolopen: (type) => {
        const info = 'devtool opened!; type =' + type;
        alert(info);
        // If you are worried about blocking the page, use console.warn(info); and open the console to view
    },
})
```

## Conclusion

disable-devtool suits someone who wants to make casual inspection of a page inconvenient rather than someone who wants it prevented, since the mechanism is a set of heuristics plus a bypass the author keeps a key to. It does not suit anyone who needs an actual security control. Before shipping it, read the returned object rather than assuming success, test it on the browsers you support, and remember that the bypass is enabled by default for the author and disabled by default for you.

## FAQ

### Why do DevTools keep popping up?

The readme covers the inverse case rather than this one: a probe firing when no tools are open, which it describes as a false trigger. Its advice is to pass a callback that reports which probe fired, and to use a console warning rather than a dialog if you do not want the page to block.

### Why are developer tools disabled in Chrome?

The library does not say what a browser does on its own account. What it documents is its own list of fourteen features, including blocking the shortcut keys, blocking the right-click, closing the page when tools are opened from the browser menu, and recognising two named in-page debugging consoles.

### How to disable JavaScript DevTools?

Install the package and call the exported function, passing an options object, which is the recommended route because a script tag can be intercepted separately by an agent. The function returns an object with a boolean saying whether it started and a string giving the reason if it did not.

### How do I deactivate the debugger?

The library supports suspending and resuming probe work, and it can be configured to ignore certain attributes so probes stay enabled in development. It also detects two specific in-page debugging consoles by name, which is the narrowest version of deactivation it offers.

### disable devtool is suspend true

Suspending probe work is one of fourteen listed features, alongside resuming it, and configuring which attributes to ignore so probes can stay enabled where you want them. The configuration also accepts a hash value and a parameter name for a bypass, and the bypass is disabled by default.

## Sources

- [License: MIT](https://github.com/theajack/disable-devtool/blob/master/LICENSE)
- [Project website](https://theajack.github.io/disable-devtool/)
- [README](https://github.com/theajack/disable-devtool/blob/master/README.md)
- [Releases](https://github.com/theajack/disable-devtool/releases)
- [theajack/disable-devtool on GitHub](https://github.com/theajack/disable-devtool)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/theajack-disable-devtool
