by Mátyás Fodor

How to outsmart incognito block


Recently I came across several sites that showed a warning or paywall because I was using incognito mode. I think it is unfair. I should be allowed to use whatever browser and mode I want. This is a way to enforce their tracking tools. I know that incognito is not safe but it’s the bare minimum you can do to avoid ads to track you.

The whole thing took me about two hours and I learned a lot about browser extensions and hacking client-side code as an end user. I thought this might be worth sharing.

First, I had to look up how to detect private mode. As per my best knowledge, there’s no browser API to detect private mode directly, so I was pretty sure it is a sneaky little script. This StackOverflow answer gave me a hint, so I knew I’d have to look for webkitRequestFileSystem. I found this bit in one of those private loathing sites’ minified JavaScript code. Here’s the exciting part:

I could test the module by pasting it in incognito and public browser window dev console and run:

var module = {};incognito(null, module);module.exports.detectIncognito().then(console.log)

Bingo! This is it, I just have to find a way not to call the error callback in window.webkitRequestFileSystem(..). The easiest way is to monkey patch the function:

(function(webkitRequestFileSystem) {  window.webkitRequestFileSystem = function(t, s, success, error) {    webkitRequestFileSystem(t, s, success, success);  }})(window.webkitRequestFileSystem);

If you’re not familiar with the technique, monkey patching is a way to add, modify, or suppress the default behavior of a piece of code at runtime without changing its original source code.

Detour 1: First I started writing my own chrome extension using Extensionizr. It’s a great tool generating Chrome extension boilerplate code. But in the end, I found an easier solution.

Whenever it comes to customizing websites I use Tampermonkey (for example hiding job ads on Stack Overflow when I really shouldn’t spend time on looking for new positions). You don’t have to install a n+1th extension, and it provides a nice interface to manage your scripts. Ok, nice is probably an exaggeration, it’s ugly but handy.

So I added the monkey patch script I referenced above, already giggling how easy it was, but bummer, it didn’t work. I tried a few other things for example:

window.foobar = 'baz';

But in the dev console, this property was absent from the window variable. It turned out content scripts are running in an isolated environment, they only share the DOM with the webpage’s scripts. I started to work with the referenced solution from SO. There was one very important thing though, I had to execute this code before the current page’s code. Here’s what I came up with:

function injectScript(file_path, node) {        var element = document.createElement('script');        element.setAttribute('type', 'text/javascript');        element.setAttribute('src', file_path);        element.setAttribute('async', false);        node.appendChild(element);}injectScript(url, document.documentElement);

Detour 2: As I started with an extension, loading another JavaScript file was trivial. However it’s not the case with Tampermonkey scripts (at least I don’t know about it). So I decided to put my code in a GitHub gist, and tried to load the raw file. But then the browser was complaining about its MIME type. Finally I ended up using, which was exactly the right tool for this.

I realized that I should add those few lines of monkey patch code as a string, and fill in the script element’s text with that. Here’s my final solution:

An important thing to know if you work with Tampermonkey in incognito mode: your changes made in incognito mode won’t appear in normal mode, and vice versa: you have to close all your private windows if you want to try your latest changes made in public mode.

Be careful! If you decide to use my script, you have to know that this might (although not very likely) break some web pages. You can always turn these off in Tampermonkey. Use it at your own risk.