We’ve all been there. Landed on a website only to be slapped with a modal that looked something like the one below:

For me that triggers a knee-jerk reaction: curse for giving them a pageview, close the tab, and never return. But there’s also that off case when we might actually try to get to the info behind that modal. So the next step in this situation is to bring up DevTools in order to delete the modal and overlay, and maybe some other useless things that clutter up the page while we’re at it.
This is where that page starts to dabble in evil.
We may not be able to get to the DevTools via “Inspect Element” because the context menu might be disabled. That one is easy, it only takes them one line of code:
addEventListener('contextmenu', e => e.preventDefault(), false);
But hey, no problem, that’s what keyboard shortcuts are for, right? Right… unless there’s a bit of JavaScript in the vein of the one below running:
addEventListener('keydown', e => {
if(e.keyCode === 123 /* F12: Chrome, Edge dev tools */ ||
(e.shiftKey && e.ctrlKey && (
e.keyCode === 73 /* + I: Chrome, FF dev tools */ ||
e.keyCode === 67 /* + C: Chrome, FF inspect el */ ||
e.keyCode === 74 /* + J: Chrome, FF console */ ||
e.keyCode === 75 /* + K: FF web console */ ||
e.keyCode === 83 /* + S: FF debugger */ ||
e.keyCode === 69 /* + E: FF network */ ||
e.keyCode === 77 /* + M: FF responsive design mode */)) ||
(e.shiftKey && (
e.keyCode === 118 /* + F5: Firefox style editor */ ||
e.keyCode === 116 /* + F5: Firefox performance */)) ||
(e.ctrlKey && e.keyCode === 85 /* + U: Chrome, FF view source */)) {
e.preventDefault();
}
}, false);
Still, nothing can be done about the browser menus. That will finally bring up DevTools for us! Hooray! Delete those awful nodes and… see how the page refreshes because there’s a mutation observer watching out for such actions. Something like the bit of code below:
addEventListener('DOMContentLoaded', e => {
let observer = new MutationObserver((records) => {
let reload = false;
records.forEach((record) => {
record.removedNodes.forEach((node) => {
if(node.id === 'overlay' && !validCustomer())
reload = true;
});
if(reload)
window.location.reload(true);
});
});
observer.observe(
document.documentElement, {
attributes: true,
childList: true,
subtree: true,
attributeOldValue: true,
characterData: true
}
);
});
“This is war!” mode activated! Alright, just change the modal and overlay styles then! Except, all the styles are inline, with !important
on top of that, so there’s no way we can override it all without touching that style
attribute.

Some people might remember about how 256 classes override an id, but this has changed in WebKit browsers in the meanwhile (still happens in Edge and Firefox though) and 256 IDs never could override an inline style anyway.
Well, just change the style
attribute then. However, another “surprise” awaits: there’s also a bit of JavaScript watching out for attribute changes:
if(record.type === 'attributes' &&
(record.target.matches &&
record.target.matches('body, #content, #overlay')) &&
record.attributeName === 'style' && !validCustomer())
reload = true;
So unless there are some styles that could help us get the overlay out of the way that the person coding this awful thing missed setting inline, we can’t get past this by modifying style
attributes.
The first thing to look for is the display
property as setting that to none
on the overlay solves all problems. Then there’s the combo of position
and z-index
. Even if these are set inline on the actual overlay, if they’re not set inline on the actual content below the overlay, then we have the option of setting an even higher z-index
value rule for the content and bring it above the overlay. However, it’s highly unlikely anyone would miss setting these.
If offsets (top
, right
, bottom
, left
) aren’t set inline, they could help us shift the overlay off the page and the same goes for margin
or translate
properties. In a similar fashion, even if they’re set inline on the overlay, but not on the actual content and on the parent of both the overlay and the content, then we can shift this parent laterally by something like 100vw
and then shift just the content back into view.
At the end of the day, even a combination of opacity
and pointer-events
could work.
However, if the person coding the annoying overlay didn’t miss setting any of these inline and we have that bit of JS… we cannot mess with the inline styles without making the page reload.
But wait! There’s something that can override inline values with !important
, something that’s likely to be missed by many… and that’s @keyframe
animations! Adding the following bit of CSS in a new or already existing style
element brings the overlay and modal behind the actual content:
#overlay { animation: a 1s infinite }
@keyframes a { { 0%, to { z-index: -1 } } }
However, there might be a bit of JavaScript that prevents us from adding new style
or link
elements (to reference an external stylesheet) or modifying already existing ones to include the above bit of CSS, as it can be seen here.
if(record.type === 'characterData' &&
record.target.parentNode.tagName.toLowerCase() === 'style')
reload = true;
record.addedNodes.forEach((node) => {
if(node.matches &&
node.matches('style:not([data-href]), link[rel="stylesheet"]'))
reload = true;
});
See the Pen How to be evil (but please don’t) by Ana Tudor (@thebabydino) on CodePen.
But if there already is an external stylesheet, we could add our bit of CSS there and, save for checking for changes in a requestAnimationFrame
loop, there is no way of detecting such a change (there have been talks about a style mutation observer, but currently, we don’t yet have anything of the kind).
Of course, the animation
property could also be set inline to none
, which would prevent us from using this workaround.
But in that case, we could still disable JavaScript and remove the overlay and modal. Or just view the page source via the browser menu. The bottom line is: if the content is already there, behind the overlay, there is absolutely no sure way of preventing access to it. But trying to anyway is a sure way to get people to curse you.
I wrote this article because I actually experienced something similar recently. I eventually got to the content. It just took more time and it made me hate whoever coded that thing.
It could be argued that these overlays are pretty efficient when it comes to stopping non-technical people, which make up the vast majority of a website’s visitors, but when they go to the trouble of trying to prevent bringing up DevTools, node deletions, style changes and the like, and pack the whole JavaScript that does this into hex on top of it all, they’re not trying to stop just non-technical people.
If they started disabling dev tools, I’d hit that back button and go to the next result in my search results.
Or just have devtools active before entering
Man you really relish pain! Be simple:
window.reload = function() { /* do nothing */ }
Ah, but
window.location.reload
is neither writable nor configurable.if you want just to read the data then you can open dev tools and trigger an event in the debugger then disable the paused state overlay (chrome). Now the page is all yours, you can change whatever you want without any JavaScript being executed
That’s actually pretty clever too. A lot of great answers in the comments. I think the article itself was more trying to demonstrate interesting properties of CSS rather than actually solve the problem of getting content from a modal blocked page.
Change content section id.
Delete inline styles.
Delete modal overlay node.
Done.
After reading half-way through…
Hmmpfff, that’s easy peasy, seen tons of those.
I’ll just click in the address bar before pressing F12.
Then inspect the overlay elements and, like always, simply press delete… POOF! Page reload! Wait, What?!
Hmm, that’s new.. Think I do need to read the rest of the article :D
Disabling JavaScript is much simpler. I have a chrome plugin so I can toggle JavaScript on and off on a site by site basis. Is especially useful on news and fan wiki sites. If you still need to, you can delete elements because there’s no JavaScript listeners running. In theory they could load the content by ajax, but usually they are usually nervous that google won’t be able to crawl the content if it’s not in the document.
Exactamundo
<noscript><meta http-equiv="refresh" content="0; url=pay-us.html" /></noscript>
Another way around this could be to use a user stylesheet in the browser, probably with most styles marked as !important to override a site’s !important styles.
Fascinating dive into these terrible practices! This code seems to hate any browser extensions that automatically add pieces/scripts to the page.
A few other workarounds by adding entries to the stylesheet:
#overlay { filter: opacity(0%); }
or#overlay { border-left: solid 100vw transparent; }
to hide the overlay,#overlay { pointer-events: none; }
to allow clicking behind.body { position: absolute; top: -1% }
then adjust thetop
value to scrollEasy enough for evil devs to add protections against, I suppose, but worth trying if you get stuck.
I wonder how long until Google detects these techniques and adds severe SEO penalties to these sites.
I believe they already are, at least on mobile: https://webmasters.googleblog.com/2016/08/helping-users-easily-access-content-on.html
Wow. That’s a lot of effort to go through to be annoying.
Here’s my solution:
Open devtools manually to elements panel.
Use the “pick an element” thingy to select an element the Pen iframe.
Peek at the DOMContentLoaded listeners to see which one is being awful (could also be done through the sources by looking for
reload
).Put a breakpoint at line 30 (
if (reload) ...
)Delete the modal
Run
reload = false
in the console at the breakpoint and continue execution.You could also set a breakpoint where the mutation observer is installed, let it reload the page once, and on the next run through just cancel it from the console immediately after it is installed. Then you’re free to abuse the DOM as you please.
My first attempt was to replace
window.location.reload
with a noop, but it’s not writable or configurable.Changing the overlay id allows you to delete it, like multiple people have said, but I noticed no one mentioned making the body content scrollable. Changing the inline styles on the element causes a page reload, but I was able to get around it by editing the html and wrapping all of the contents of body in a div which was then set to:
height: 100vh;
overflow-y: scroll;
You can also just style the
<html>
tagIsn’t easier to simply associate a custom style sheet to the web site? I use stylish for that and it works great. CSS examples for paywall removal: https://userstyles.org/styles/browse?search_terms=remove%20paywall
Server side rendering – nothing to find here, move along :)
I find the Reading View in Safari, Firefox, and Edge to be super helpful for cases like this, too. They can’t do anything about that.
I’d try using a browser extension. I already have TamperMonkey and Stylish installed and could use one of them to inject something that manipulated the popup.
Or perhaps I’d try just opening the page in Lynx. :)
Cool article! If I ever want to have a look at page code I just view-source, normally none of these are ever worth looking in to!
Super interesting article! I’ve experienced similar pop ups but have always been able to delete them via DevTools if I really want to see the content.
Another easy workaround is if they’re asking for an email address, just enter
[email protected]
so you can sign them up to their own newsletter and then read the content! Or as others have suggested, just go to a different website. They’ll soon get the picture when their bounce rate jumps.To me it is specially evil when what it’s behind the modal is actually not the actual content, but a blurry static image. Damn you, clever developers!
You could also use a proxy service like Charles. Download their JavaScript file, remove the lines watching for mutations, and replace their version with yours. I’d prefer this over turning JavaScript off entirely so that I could continue to use sites that may use JS for routing or other positive functionality.
My solution would be to open up devtools and then disable JS. Reload the page and then just remove the element.
Won’t work if the site is an SPA and depends on JS. In that case a breakpoint will be required.
Another easy workaround is if they’re asking for an email address, just enter [email protected] so you can sign them up to their own newsletter and then read the content! Or as others have suggested, just go to a different website. They’ll soon get the picture when their bounce rate jumps.
If you are evil you can also:
reload page immediatly when anyone is trying to open devtools (console-bug with getters).
reload page when any of page content from the bottom of the page is showed (by scroll?) while popup “is visible”.
reload page if popup coordinates became incorrect
If you wanna to read article and you can’t simply disable javascript (cause you need to wait of delivery the ajax-content) you can try to do next:
write some extension for this site which will produce “alert” when you need it. Alert is stopping js-thread. On this moment you can open chrome-dev-tools without reloading page immeditaly (that console.log bug with getters of the object)
simply copy total html of the page and paste it anywhere you want.
read it, enjoy :)
Also you can monitoring xhr-network requests by wire-shark. Or your extensions can copy and sent body.innerHTML to your server. Also you simply can disable custom js-file, you can proxy this website and replace js-query content on the fly. You can do a lot of vary things. You can open dev-tools before loading the evil-site. Recap: evil-guy can’t forbid your access to his public content :)
But… Browsers have bugs. Some of them is critical. If this guy so evil, may be he knows some of them. He can break your system by zero-day vulnerability? :)
P.S. sorry for my bad english
Why not just disable JavaScript for that website?
Nice one, I didn’t knew half these “techniques” existed.
One easy way to hide them without triggering mutation events and whatnot is to select the element in DevTools and pressing “H” to let chrome hide them which should work despite inline !important styles.
Just by opening the codepen provided in the article you can see that “Hide element” option still reloads the page, so it’s not a solution.
What’s with a simple Menu > View > Disable CSS Styles (or wherever your browser hides it)? It may be as effective a the reader view.
Now how often do you go to all of that work and then realize the content behind this overlay is worthless?
You could possibly use the animation API
Fun to hack for it, but I just open DevTols, Network tab, filter for the content , e.g. Media, right click, Open in New Tab.
This is…hands down, the most thoughtful and entertaining article with comments I’ve read in 20 years.
A lot of answers here go along the line: “Attach a style sheet/remove a script/change that attribute/style” or just offer a solution for that specific site.
But the point here isn’t just that site: it’s the more general problem of sites that want you to see that modal and will do all that it takes to make it so. In short, assume that you can’t touch the DOM in any way. So, what can we do?
Stylish is out of question. A solution would be injecting some CSS rules into an existing style sheet using Grease/TamperMonkey, but they won’t save you from inline styles.
Another nice extension that could do the trick is uMatrix, that can disable scripts selectively. Not really easy to use, though, and results may vary.
A nice technique would require tampering with DOM methods like
appendChild
and the sort, or even overriding functions likesetTimeout
or classes likeMutationObserver
, depending on the case. Of course that can disrupt the est of the page too, but it’s a good start to see how to target the right culprit.I’ve done this for far too long. Anti-adblockers are the worst…
Nice challenge!
Add a break point on each
reload = true
then delete node when execution stop at one of thereload=true
now step over one step by devtool and makereload=false
by console and it worksI can appreciate the dedication of that bored developer.
Just change ID and change any inline CSS you would like.
LOL, this article and subsequent conversation are awesome. EVERYONE hates websites that do this stuff. I’ve been using console/devtools to bypass such idiocy for years. Particularly annoying ads? F12>find offending node>DEL. Video containers that won’t stop playing video? F12>find offending iframe>DEL. Someone above mentioned the breakpoint>pause method, someone else mentioned the F12>Sources>locate media node>open in new window method…changing object position, page layout, ID values, adding/modifying styles, spamming the signup form in the modal with the tld admin email address, this stuff is hilarious. I’ve used several of these methods to defeat nefarious garbage like the modal in question. I think it’s even more amusing that Ana Tudor penned this one (mad props to Ana for her polygon animations and utilization of Beyond Mere Mortals Maths!).
This post reminds me of late-90’s client requests to “keep visitors from viewing source” – what? Why, though? Is something in your code diabolical, dangerous, precious? Are you trying to hide State Secrets in rendered code?
At some point, before getting to the content we want and then forever abandoning the offending website, we must ask ourselves: are websites which use this content-protected-by-stupidity model REALLY worth our time to visit, or are we better off seeking an alternate source of content? Some content is only available from one provider, but this perma-modal stuff is not worth my time, and their content is probably not worth my time, either.
I’ve never understood why anyone would think, before a visitor has even started reading your content, you would slap them in the face with a modal (subscribe! etc etc).
This is even more diabolical.
Then there are sites like Forbes, who force ads on you, but don’t ensure that you aren’t being served ads with malware and malicious code embedded in them. If I can’t relatively easily use devtools to read the content, I just move on. There is no content that is so precious and special that I need to risk malware or being harangued with spammy email. Yes, I get that folks need to pay for producing the content, and there are some content sites I pay for because I visit often. They are few and far between.
element.style {
overflow: scroll;
height: 100%;
}
Bye bye article paywalls, sorry writers
Simple. Close tab and never return to their site.
Easy: Just style the modal with
clip: rect(1px, 1px, 2px, 2px);