Advanced Ad Tracker Logger

Logs and exports all ad/tracker URLs (.js, links, redirects, fetch) with download support even on redirecting pages

// ==UserScript==
// @name         Advanced Ad Tracker Logger
// @namespace    elite.scan.logger.v2
// @version      2.0
// @description  Logs and exports all ad/tracker URLs (.js, links, redirects, fetch) with download support even on redirecting pages
// @author       Abdelali
// @match        *://*/*
// @grant        GM_download
// ==/UserScript==

(function () {
    'use strict';

    const findings = {
        scripts: [],
        adLinks: [],
        externalLinks: [],
        redirects: [],
    };

    const adKeywords = ['ads', 'adserver', 'doubleclick', 'tracker', 'analytics', 'revbid', 'coinzilla', 'adskeeper', 'banner', 'prebid', 'rtb'];

    function isAdOrTracker(url) {
        return adKeywords.some(kw => url.toLowerCase().includes(kw));
    }

    function logFinding(type, url, context = '') {
        if (!findings[type].some(entry => entry.url === url)) {
            findings[type].push({ url, context });
        }
    }

    // Watch script injections
    const scanDOM = () => {
        try {
            document.querySelectorAll('script[src]').forEach(script => {
                const src = script.src;
                if (isAdOrTracker(src)) {
                    logFinding('scripts', src, 'script tag');
                }
            });

            document.querySelectorAll('a[href]').forEach(link => {
                const href = link.href;
                if (isAdOrTracker(href)) {
                    logFinding('adLinks', href, 'anchor');
                } else if (href.startsWith('http') && new URL(href).hostname !== location.hostname) {
                    logFinding('externalLinks', href, 'external anchor');
                }
            });

            // Try to inspect iframes
            document.querySelectorAll('iframe').forEach(iframe => {
                try {
                    const doc = iframe.contentDocument;
                    if (doc) {
                        doc.querySelectorAll('script[src]').forEach(script => {
                            if (isAdOrTracker(script.src)) {
                                logFinding('scripts', script.src, 'iframe script');
                            }
                        });
                    }
                } catch (e) {
                    // cross-origin, skip silently
                }
            });
        } catch (e) {}
    };

    const observer = new MutationObserver(scanDOM);
    observer.observe(document, { childList: true, subtree: true });

    setInterval(scanDOM, 3000); // Catch delayed loads

    // Hook fetch & XHR
    const origFetch = window.fetch;
    window.fetch = function () {
        const url = arguments[0];
        if (typeof url === 'string' && isAdOrTracker(url)) {
            logFinding('scripts', url, 'fetch');
        }
        return origFetch.apply(this, arguments);
    };

    const origOpen = XMLHttpRequest.prototype.open;
    XMLHttpRequest.prototype.open = function (method, url) {
        if (isAdOrTracker(url)) {
            logFinding('scripts', url, 'XHR');
        }
        return origOpen.apply(this, arguments);
    };

    // Catch redirections
    ['pushState', 'replaceState'].forEach(fn => {
        const orig = history[fn];
        history[fn] = function () {
            const url = arguments[2];
            if (typeof url === 'string' && isAdOrTracker(url)) {
                logFinding('redirects', url, `history.${fn}`);
            }
            return orig.apply(this, arguments);
        };
    });

    window.addEventListener('hashchange', () => {
        const url = location.href;
        if (isAdOrTracker(url)) {
            logFinding('redirects', url, 'hashchange');
        }
    });

    // Export function with force download using Blob
    function forceDownload(content, filename = 'ad_scan.json') {
        const blob = new Blob([content], { type: 'application/json' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = filename;
        a.style.display = 'none';
        document.body.appendChild(a);
        a.click();
        setTimeout(() => {
            URL.revokeObjectURL(url);
            a.remove();
        }, 1000);
    }

    // Button
    window.addEventListener('load', () => {
        const btn = document.createElement('button');
        btn.textContent = '📦 Export Ads Log';
        Object.assign(btn.style, {
            position: 'fixed',
            bottom: '20px',
            right: '20px',
            zIndex: 999999,
            padding: '10px',
            background: '#111',
            color: '#fff',
            border: 'none',
            borderRadius: '5px',
            cursor: 'pointer',
        });

        btn.onclick = () => {
            const data = JSON.stringify(findings, null, 2);
            forceDownload(data, `ad_scan_${location.hostname}.json`);
        };

        document.body.appendChild(btn);
    });
})();