GTM Injector

Injects a GTM container with a dynamic ID, visual feedback, and advanced debugging for testing purposes.

// ==UserScript==
// @name         GTM Injector
// @namespace    http://tampermonkey.net/
// @version      1.0.0
// @description  Injects a GTM container with a dynamic ID, visual feedback, and advanced debugging for testing purposes.
// @author       johncarter2021
// @license      MIT
// @homepageURL  
// @supportURL   
// @match        *://*.*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// ==/UserScript==

(function () {
    'use strict';

    // --- IMPROVEMENT: Dynamic Configuration ---
    // Use Tampermonkey's storage to allow changing the GTM ID without editing the script.
    const CONFIG = {
        defaultGtmId: 'GTM-WVX6GFMQ', // A fallback ID
        get gtmId() {
            // GM_getValue can be synchronous if the value is already cached.
            return GM_getValue('utsGtmId', this.defaultGtmId);
        },
        set gtmId(id) {
            GM_setValue('utsGtmId', id);
        }
    };

    // --- IMPROVEMENT: Menu Command for Configuration ---
    // Adds an option in the Tampermonkey extension menu to change the GTM ID.
    GM_registerMenuCommand('Set UTS GTM ID', () => {
        const newId = prompt('Enter the new GTM Container ID:', CONFIG.gtmId);
        if (newId && newId.trim().toUpperCase().startsWith('GTM-')) {
            CONFIG.gtmId = newId.trim();
            alert(`GTM ID set to ${CONFIG.gtmId}. The page will now reload.`);
            location.reload();
        } else if (newId) {
            alert('Invalid GTM ID format. It should start with "GTM-".');
        }
    });


    // --- SCRIPT EXECUTION ---
    const gtmId = CONFIG.gtmId; // Get the currently configured GTM ID

    // Prevent re-injection
    if (window.utsGtmInjected || document.querySelector(`script[src*="gtm.js?id="]`)) {
        // Check for ANY GTM script, not just ours, to avoid conflicts.
        console.log('%c UTS GTM Injector: A GTM container is already on this page. Aborting.', 'color: orange;');
        return;
    }
    window.utsGtmInjected = true;

    console.log(
        `%c UTS Injecting GTM Container: ${gtmId}`,
        'color: blue; font-weight: bold;'
    );

    // 1. Set up dataLayer and Consent Mode v2
    window.dataLayer = window.dataLayer || [];
    function gtag() { dataLayer.push(arguments); }
    gtag('consent', 'default', { ad_storage: 'denied', analytics_storage: 'denied' });
    window.dataLayer.push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });

    // 2. Inject GTM Head Script
    function injectGtmHeadScript() {
        const head = document.head;
        const gtmScript = document.createElement('script');
        gtmScript.async = true;
        gtmScript.src = `https://www.googletagmanager.com/gtm.js?id=${gtmId}`;
        head.insertBefore(gtmScript, head.firstChild);
        console.log('%c UTS QA: GTM head script injected successfully.', 'color: green;');
    }

    // 3. Inject GTM Body Noscript
    function injectGtmBodyNoscript() {
        const body = document.body;
        const noscript = document.createElement('noscript');
        const iframe = document.createElement('iframe');
        iframe.src = `https://www.googletagmanager.com/ns.html?id=${gtmId}`;
        iframe.height = '0';
        iframe.width = '0';
        iframe.style.cssText = 'display:none;visibility:hidden';
        noscript.appendChild(iframe);
        body.insertBefore(noscript, body.firstChild);
        console.log('%c UTS QA: GTM noscript injected successfully.', 'color: green;');
    }

    // --- IMPROVEMENT: Visual Feedback Indicator ---
    function createVisualIndicator() {
        // Use GM_addStyle to inject CSS without polluting the DOM with <style> tags
        GM_addStyle(`
            #uts-gtm-indicator {
                position: fixed;
                bottom: 10px;
                right: 10px;
                background-color: #007bff;
                color: white;
                padding: 8px 12px;
                border-radius: 5px;
                font-family: sans-serif;
                font-size: 12px;
                z-index: 999999;
                box-shadow: 0 2px 5px rgba(0,0,0,0.2);
                cursor: pointer;
                transition: background-color 0.2s;
            }
            #uts-gtm-indicator:hover {
                background-color: #0056b3;
            }
        `);

        const indicator = document.createElement('div');
        indicator.id = 'uts-gtm-indicator';
        indicator.textContent = `UTS GTM: ${gtmId}`;
        indicator.title = 'Click to open GTM Debug Mode';

        // --- IMPROVEMENT: One-Click Debug Link ---
        indicator.addEventListener('click', () => {
            const debugUrl = new URL(window.location.href);
            debugUrl.searchParams.set('gtm_debug', new Date().getTime()); // Add debug param
            window.open(debugUrl.href, '_self'); // Open in the same tab
        });

        document.body.appendChild(indicator);
        console.log('%c UTS QA: Visual indicator created.', 'color: green;');
    }

    // --- IMPROVEMENT: Advanced CSP Error Detection ---
    function listenForCspErrors() {
        document.addEventListener('securitypolicyviolation', (e) => {
            if (e.blockedURI.includes('googletagmanager.com')) {
                console.error(
                    '%c UTS QA: GTM script was BLOCKED by the site\'s Content Security Policy (CSP). Check the console for details on the "Content-Security-Policy" header.',
                    'color: red; font-weight: bold; font-size: 14px;'
                );
                // Optionally update the visual indicator
                const indicator = document.getElementById('uts-gtm-indicator');
                if (indicator) {
                    indicator.textContent += ' (CSP Blocked!)';
                    indicator.style.backgroundColor = '#dc3545'; // Red color
                    indicator.title = 'GTM was blocked by the site\'s Content Security Policy.';
                }
            }
        });
    }

    // --- EXECUTION FLOW ---
    injectGtmHeadScript();
    listenForCspErrors(); // Start listening for errors right away.

    // Wait for the DOM to be ready before injecting into the <body>
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => {
            injectGtmBodyNoscript();
            createVisualIndicator();
        });
    } else {
        injectGtmBodyNoscript();
        createVisualIndicator();
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址