Greasy Fork is available in English.

Twitter Ad Remover

Remove promoted tweets and ads from Twitter feed

// ==UserScript==
// @name         Twitter Ad Remover
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Remove promoted tweets and ads from Twitter feed
// @author       aspen138
// @match        *://twitter.com/*
// @match        *://x.com/*
// @grant        none
// @license      MIT
// @icon                  https://about.twitter.com/etc/designs/about2-twitter/public/img/favicon-32x32.png
// ==/UserScript==

(function() {
    function hideAd(node) {
        if (
            !node ||
            node.nodeName !== "DIV" ||
            node.getAttribute("data-testid") !== "cellInnerDiv"
        ) {
            return;
        }

        const adArticle = node.querySelector("div[data-testid='placementTracking'] > article");
        if (!adArticle) {
            return;
        }

        node.style.cssText += "display: none;";
    }

    // Observe for newly added nodes and hide ads in them
    new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            mutation.addedNodes.forEach(hideAd);
        });

        // Hide the sidebar ad
        const sidebarAd = document.querySelector("#react-root > div > div > div.css-175oi2r.r-1f2l425.r-13qz1uu.r-417010.r-18u37iz > main > div > div > div > div.css-175oi2r.r-aqfbo4.r-10f7w94.r-1hycxz > div > div.css-175oi2r.r-1hycxz.r-gtdqiz > div > div > div > div:nth-child(3) > div > aside");
        if (sidebarAd) {
            sidebarAd.style.display = 'none';
        }
    }).observe(document.body, {
        childList: true,
        subtree: true
    });

    // Initial pass to hide existing ads
    document.querySelectorAll("div[data-testid='cellInnerDiv']").forEach(hideAd);

    function removePromotedTweets(node) {
        node = node || document.body;
        const tweets = node.querySelectorAll('article[data-testid="tweet"]');

        tweets.forEach((tweet) => {
            const adLabel = tweet.querySelector('div[dir="ltr"] > span');
            if (adLabel && (adLabel.textContent === 'Promoted' || adLabel.textContent === 'Ad')) {
                tweet.remove();
            }
        });
    }

    // Initial removal of promoted tweets
    removePromotedTweets();

    // Observe the DOM for changes and remove newly added promoted tweets
    new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            mutation.addedNodes.forEach(function(node) {
                if (node.nodeType === Node.ELEMENT_NODE) {
                    removePromotedTweets(node);
                }
            });
        });
    }).observe(document.body, {
        childList: true,
        subtree: true
    });
})();