In a world where technology becomes more utterly fucked every day, userscripts can feel liberating. You don’t know what are userscripts? They’re tiny (or not) javascript scripts that you can inject into any web page. Kinda like a browser plugin, but usually hyper-focused to change specific behaviors or visuals on specific sites.

They’re a great way to take back a bit of control.

You can use them by installing a userscripts manager like Tampermonkey (it’s the one I use).


Now what about a few examples?

Reddit

Reddit is a mess (to put it gently), you know your health would be better if you stopped interacting with it, but it’s still a useful resource. Rejoice, here’s a script for old.reddit.com to disable the reply button and that useless notification icon!

// ==UserScript==
// @name         Better reddit
// @version      2025-07-10
// @description  Less annoyances and lower blood pressure
// @author       scambier.xyz
// @match        https://www.reddit.com/*
// @match        https://old.reddit.com/*
// @icon         https://www.reddit.com/favicon.ico
// @grant        none
// ==/UserScript==
 
(function() {
    'use strict';
    setTimeout(() => {
        // You don't care about notifications
        $('#notifications').next('.separator').remove()
        $('#notifications').remove()
        $('.message-count.badge-count').remove()
 
        // Read-only mode
        $('li.reply-button').remove()
        $('div.usertext-edit').remove()
    }, 100)
})();

itch.io

You like to browse itch.io for quirky games, assets, or inspiration, but you can’t stand the neverending horror and visual novel slops when you’re browsing the site? This script will automatically filter out the horror tag, and dynamically remove visual novels as you scroll down.

// ==UserScript==
// @name         Filter games on itch.io
// @version      2024-06-24
// @description  Filter out games with a specific tag on itch.io
// @author       scambier.xyz
// @match        https://itch.io/games
// @match        https://itch.io/games?*
// @match        https://itch.io/games/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=itch.io
// @grant        none
// @license      MIT
// ==/UserScript==
 
(function() {
    'use strict';
 
    // Filtering tags only works one tag at a time
    const url = new URL(window.location.href);
    const exclude = url.searchParams.get("exclude");
    if (!exclude) {
        url.searchParams.set("exclude", "tg.horror");
        window.location.href = url.href;
    }
 
 
    const EXCLUDED_GENRES = [
        'visual novel',
    ];
 
    const removeExcludedGenres = () => {
        $('div.game_genre').filter(function() {
            const genreText = $(this).text().toLowerCase();
            return EXCLUDED_GENRES.some(genre => genreText.includes(genre));
        }).closest('div.game_cell').remove();
    };
 
    // Observer to also delete when scrolling and loading new games
    const observeChanges = () => {
        new MutationObserver(removeExcludedGenres).observe(document.body, {
            childList: true,
            subtree: true
        });
    };
 
    removeExcludedGenres();
    observeChanges();
})();

Hackernews

The “orange hell site” is terrible and I don’t visit often it anymore, but I like this snippet: it adds icons to quickly see the links with the most votes or comments.

"use strict";
/* globals jQuery, $, waitForKeyElements */
// ==UserScript==
// @name         Hacker News - Most upvoted & most commented links
// @namespace    https://github.com/scambier/userscripts
// @downloadURL  https://github.com/scambier/userscripts/raw/refs/heads/master/dist/hackernews.user.js
// @updateURL    https://github.com/scambier/userscripts/raw/refs/heads/master/dist/hackernews.user.js
// @author       scambier.xyz
// @version      0.0.10
// @description  Show top 🔥👄 links of Hacker News
// @license      ISC
// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js
// @match        https://news.ycombinator.com/
// @match        https://news.ycombinator.com/ask*
// @match        https://news.ycombinator.com/news*
// @match        https://news.ycombinator.com/show*
// @match        https://news.ycombinator.com/front*
// @grant        none
// @run-at       document-end
// ==/UserScript==
(() => {
    // Firefox mobile fix, do nothing if icons are already injected
    if ([...$('[data-userscript="scambier"]')].length)
        return;
    const rows = [...$("tr.athing")];
    // Select lines
    const items = rows
        // Filter out ads
        .filter((tr) => $(tr).find("td.votelinks").length)
        // Get id and score
        .map((tr) => {
        var _a, _b;
        return {
            id: $(tr).attr("id"),
            score: Number((_a = $(tr).next().find(".score")[0].textContent) === null || _a === void 0 ? void 0 : _a.split(" ")[0]),
            // Weirdly, .split(' ') does not work
            comments: Number((_b = $(tr)
                .next()
                .find('a:contains("comments")')
                .text()
                .split("comments")[0]
                .trim()) !== null && _b !== void 0 ? _b : 0),
        };
    });
    // Top 10% for new entries, top 20% for other pages
    const ratio = location.href.includes("news.ycombinator.com/newest")
        ? 0.1
        : 0.2;
    // Inject icons
    items.forEach((o) => {
        const title = $(`tr#${o.id}`).find("span.titleline");
        if (getTop(items, "comments", ratio).includes(o) && o.comments > 0) {
            title.before('<span title="Most commented" data-userscript="scambier">👄 </span>');
        }
        if (getTop(items, "score", ratio).includes(o) && o.score > 0) {
            title.before('<span title="Most upvoted" data-userscript="scambier">🔥 </span>');
        }
    });
    /**
     * Get [ratio] best [items], ordered by [key]
     *
     * @param items
     * @param key
     * @param ratio
     */
    function getTop(items, key, ratio) {
        const count = rows.length;
        return [...items].sort((a, b) => b[key] - a[key]).slice(0, count * ratio);
    }
})();