Created
August 13, 2025 08:23
-
-
Save nikspyratos/a340af08e1a72acf76ce981f0900554c to your computer and use it in GitHub Desktop.
Twitter/X anti-doomscroll tampermonkey script (Claude vibes)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name X Anti-Doomscroll Script | |
| // @namespace http://tampermonkey.net/ | |
| // @version 1.0 | |
| // @description Force Following tab and hide For You tab to reduce doomscrolling | |
| // @author You | |
| // @match https://twitter.com/* | |
| // @match https://x.com/* | |
| // @grant none | |
| // @run-at document-start | |
| // ==/UserScript== | |
| (function() { | |
| 'use strict'; | |
| // Function to hide For You tab and ensure Following is active | |
| function modifyTabs() { | |
| // Common selectors for the tab navigation | |
| const tabSelectors = [ | |
| '[data-testid="ScrollSnap-List"]', | |
| '[role="tablist"]', | |
| 'nav[role="navigation"] div[role="tablist"]' | |
| ]; | |
| let tabContainer = null; | |
| // Find the tab container | |
| for (const selector of tabSelectors) { | |
| tabContainer = document.querySelector(selector); | |
| if (tabContainer) break; | |
| } | |
| if (tabContainer) { | |
| const tabs = tabContainer.querySelectorAll('[role="tab"]'); | |
| tabs.forEach(tab => { | |
| const tabText = tab.textContent.trim().toLowerCase(); | |
| // Hide "For you" tab | |
| if (tabText.includes('for you') || tabText.includes('foryou')) { | |
| tab.style.display = 'none'; | |
| console.log('Hidden For You tab'); | |
| } | |
| // Ensure "Following" tab is visible and active | |
| if (tabText.includes('following')) { | |
| tab.style.display = 'block'; | |
| // Click Following tab if it's not already selected | |
| if (!tab.getAttribute('aria-selected') || tab.getAttribute('aria-selected') === 'false') { | |
| console.log('Clicking Following tab'); | |
| tab.click(); | |
| } | |
| } | |
| }); | |
| } | |
| } | |
| // Function to redirect if on For You timeline | |
| function checkAndRedirectFromForYou() { | |
| const currentPath = window.location.pathname; | |
| // If we're on the home page (which defaults to For You), redirect to Following | |
| if (currentPath === '/home' || currentPath === '/') { | |
| const followingTab = document.querySelector('[role="tab"][aria-selected="false"]'); | |
| if (followingTab && followingTab.textContent.toLowerCase().includes('following')) { | |
| followingTab.click(); | |
| } | |
| } | |
| } | |
| // CSS to hide For You tab more aggressively | |
| function addCustomCSS() { | |
| const style = document.createElement('style'); | |
| style.textContent = ` | |
| /* Hide For You tab by text content */ | |
| [role="tab"]:has-text("For you"), | |
| [role="tab"]:has-text("For You") { | |
| display: none !important; | |
| } | |
| /* Alternative approach using attribute selectors */ | |
| [data-testid*="foryou"], | |
| [data-testid*="ForYou"] { | |
| display: none !important; | |
| } | |
| /* Hide any tab that might be the first one (usually For You) */ | |
| [role="tablist"] [role="tab"]:first-child { | |
| display: none !important; | |
| } | |
| /* Ensure Following tab is visible */ | |
| [role="tab"][aria-label*="Following"], | |
| [role="tab"]:has-text("Following") { | |
| display: block !important; | |
| } | |
| `; | |
| document.head.appendChild(style); | |
| } | |
| // Initialize when page loads | |
| function initialize() { | |
| addCustomCSS(); | |
| // Run modifications immediately | |
| modifyTabs(); | |
| checkAndRedirectFromForYou(); | |
| // Set up observers for dynamic content | |
| const observer = new MutationObserver((mutations) => { | |
| let shouldCheck = false; | |
| mutations.forEach((mutation) => { | |
| if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { | |
| shouldCheck = true; | |
| } | |
| }); | |
| if (shouldCheck) { | |
| setTimeout(() => { | |
| modifyTabs(); | |
| checkAndRedirectFromForYou(); | |
| }, 100); | |
| } | |
| }); | |
| // Start observing | |
| observer.observe(document.body, { | |
| childList: true, | |
| subtree: true | |
| }); | |
| // Also run periodically as a fallback | |
| setInterval(() => { | |
| modifyTabs(); | |
| }, 2000); | |
| } | |
| // Wait for page to be ready | |
| if (document.readyState === 'loading') { | |
| document.addEventListener('DOMContentLoaded', initialize); | |
| } else { | |
| initialize(); | |
| } | |
| // Handle navigation changes (SPA routing) | |
| let currentUrl = location.href; | |
| new MutationObserver(() => { | |
| if (location.href !== currentUrl) { | |
| currentUrl = location.href; | |
| setTimeout(initialize, 500); | |
| } | |
| }).observe(document, { subtree: true, childList: true }); | |
| })(); |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Made with Claude.
I want to use X, but not get sucked into the algorithmic feed at all costs.
Features
Usage
Issues
Haven't noticed any, but if you use this and find any let me know!
Notes
Vibe coded one for Instagram too: https://gist.github.com/nikspyratos/3c5b82d24e835d63419700d26db0e696
For Youtube on web, I recommend Unhook.
For Android, I recommend ScreenZen - it can block specifically the short form video sections of Instagram and Youtube.