I've created a mutation observer to remove (block) scripts under certain conditions.
There are several SO solutions which suggest it can work. Eg: https://stackoverflow.com/a/65453574/4688612
But it doesn't work in my case for <script src="https://www.googletagmanager.com/gtag/js?id=UA-12345678-9"></script>
For some reason the network call to googletagmanager.com still happens on every page load.
Google Chrome and Firefox both load the script.
Now I'm not sure if using the mutation observer method is simply not reliable or buggy, or if it is a bug in my code.
Is there a reliable solution for this?
Here's my code.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="shortcut icon" href="#">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj 3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous">
</script>
<script>
const observer = new MutationObserver( (mutations) =>{
mutations.forEach(({addedNodes}) => {
[...addedNodes]
.forEach(node => {
$(node).remove()
});
});
})
observer.observe(document.head, { childList: true });
</script>
<script src="https://www.googletagmanager.com/gtag/js?id=UA-12345678-9"></script>
</head>
<body></body>
</html>
```
CodePudding user response:
Testing this locally
This is maybe not an answer but I cannot illustrate in a comment what may be the issue here.
I have created an index.html just as yours but with a locally loaded script test.js
. I also added console.log(node);
in your observer.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MutationObserver test</title>
<link rel="shortcut icon" href="#">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj 3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script>
const observer = new MutationObserver( (mutations) =>{
mutations.forEach(({addedNodes}) => {
[...addedNodes]
.forEach(node => {
console.log(node);
$(node).remove()
});
});
});
observer.observe(document.head, { childList: true });
</script>
<script src="test.js"></script>
</head>
<body></body>
</html>
test.js
console.log("I got loaded before you could remove me.");
This results in the following console log:
index.html:21 " "
index.html:21 <script src="test.js"></script>
index.html:21 " "
So the observer is working, as it also catches empty nodes with just whitespace characters.
However in the Network tab the test.js
is still listed as loaded:
Name Status Type Initiator Size Time
index.html Finished document Other 972 B 1 ms
test.js Finished script index.html 56 B 3 ms
jquery-3... 200 script index.html 31.0 kB 10 ms
index.html Finished text/html Other 972 B 1 ms
It seems as though the HTML node was removed, the browser is prefetching the code. This likely happens because the HTML document itself will transfer regardless. Then the browser parses the HTML and sees all files to be requested. As soon as the HTML document is turned into a DOM the browser runs the observer, removes the node and just in time will not execute the JavaScript from the nodes after the observer.
See this counterexample where I comment out the observing part:
// observer.observe(document.head, { childList: true });
In this case the console output will read:
test.js:1 I got loaded before you could remove me.
The network panel will look nothing different. So it seems as I'm using Chrome, it tries to perfect speed and will load and cache the JavaScript but it will not execute it since its node got removed.
Possible TagManager / Google Anyltics insights
If you have access to alter the TagManager's tags you might just add <script>console.log("TagManager code executed");</script>
and confirm this way code execution is correctly suppressed for the removed tag. So confirming the same as my example with a local JS file but in TagManager directly.
Another way is Google TagManager's excellent Debug mode.
If Google Analytics is used here as well you might see your requests (or lack thereof) in the GA Real-Time view (well... bad documentation with no screenshots. Just look for real-time in Analytics you will find it).
CodePudding user response:
Try with following solution
Add defer
or async
to google tag manager script tag. this make google tag manager script after page load.
<script src="https://www.googletagmanager.com/gtag/js?id=UA-12345678-9"></script>
Changed to
<script defer src="https://www.googletagmanager.com/gtag/js?id=UA-12345678-9"></script>
or
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-12345678-9"></script>
Also call your removing script for the google tag manager code, this will make sure you script will load before google tag manager script load.
Learn more about defer
and async
Click Here
Following code is working fine for me
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="shortcut icon" href="#">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj 3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous">
</script>
<script>
const observer = new MutationObserver( (mutations) =>{
mutations.forEach(({addedNodes}) => {
[...addedNodes]
.forEach(node => {
$(node).remove()
});
});
})
observer.observe(document.head, { childList: true });
</script>
<script defer src="https://www.googletagmanager.com/gtag/js?id=UA-12345678-9"></script>
</head>
<body></body>
</html>