Home > Mobile >  How to remove a script tag reliably before it is loaded?
How to remove a script tag reliably before it is loaded?

Time:11-05

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 deferand 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>
  • Related