I run Invidious on a TrueNAS SCALE box at home so my YouTube subscriptions stay free of ads, tracking, and the algorithm’s mood swings. The one thing that still ruined the feed was Shorts. Half the page was a wall of clips I had no intention of watching.
I assumed there’d be a setting. There isn’t. Upstream has three feature requests asking for one (#3920, #4457, #3541) and all three are closed as “not planned”. The TrueNAS app just wraps stock Invidious, so the app GUI offers nothing either.
That leaves a client-side fix.
Why the existing filter lists don’t work#
The first thing I tried was pointing the well-known uBlock Origin lists at my instance. gijsdev/ublock-hide-yt-shorts and similar lists are great on youtube.com itself. On Invidious they did nothing.
The reason is in the markup. Invidious normalises every video URL to /watch?v=ID. There’s no /shorts/ anywhere in the page, no ytd-reel-shelf-renderer, no YouTube class names at all. The lists are matching DOM that simply isn’t there.
What the Invidious DOM actually looks like#
So I opened DevTools on my subscriptions page and inspected a few cards. They’re all the same shape:
<div class="pure-u-1 pure-u-md-1-4">
<div class="h-box">
<div class="thumbnail">
<a href="/watch?v=...">
<img class="thumbnail" src="/vi/.../mqdefault.jpg" alt="">
</a>
<div class="bottom-right-overlay">
<p class="length">1:49</p>
</div>
</div>
<div class="video-card-row">
<a href="/watch?v=..."><p>How GCA will bring value to the nation</p></a>
</div>
<!-- channel name, views, age, etc. -->
</div>
</div>Nothing in that markup labels a card as a Short. But two patterns showed up over and over when I scrolled a long feed:
- Creators who upload Shorts often tag the title with
#shorts,#comedyshorts,#shortvideoor similar. - Pure Shorts almost always have a duration under sixty seconds, rendered as
0:XXinside.bottom-right-overlay .length.
Neither signal is perfect. The hashtag rule misses Shorts from creators who don’t tag them. The duration rule occasionally eats a legitimate one-minute trailer. Together they kill most of the noise.
The filters#
uBlock Origin’s procedural cosmetic filters can match both. This is what I pasted into Dashboard, then My filters, scoped to my LAN IP:
! Invidious 192.168.1.83 -- hide Shorts
192.168.1.83##.pure-u-1.pure-u-md-1-4:has(.video-card-row a p:has-text(/#shorts?\b/i))
192.168.1.83##.pure-u-1.pure-u-md-1-4:has(.bottom-right-overlay .length:has-text(/^0:\d{2}$/))The first rule kills any card whose title text contains #short or #shorts, case-insensitive. The second kills any card whose duration starts with 0: followed by exactly two digits, i.e. anything under a minute.
uBO matches by hostname only, so the port (:31008 in my case) doesn’t go in the filter. Replace the IP with whatever you reach your Invidious on.
Things to know before you copy this#
A few sharp edges:
:has-text()is a procedural cosmetic filter. It works in full uBlock Origin on Firefox, and on Chromium for as long as MV2 lasts, but not in uBO Lite or any other Manifest V3 declarative blocker.- Some Shorts come back with an empty
.bottom-right-overlayand no.lengthat all. Live streams also have no duration, so I deliberately don’t blanket-hide that case. The hashtag rule picks the Shorts off the empty-overlay pile when the title cooperates. - Anything between 1:00 and 3:00 that’s a Short with no hashtag will slip through. YouTube allows Shorts up to three minutes now and the Invidious DOM doesn’t expose aspect ratio. If you really want those gone, you’d need a userscript that fetches each thumbnail and measures dimensions, which is more effort than I cared to spend.
- If a stubborn Short does slip through, right-click → Block element will let uBO write a selector for you. Keep new rules general (match the title pattern, not a specific video ID) or your filters list will grow forever.
What didn’t make the cut#
I considered a server-side fix too: putting nginx or Caddy in front of the SCALE app and using sub_filter (or Caddy’s replace) to inject the CSS into every response. That would cover phones and the TV without anything installed on the client. I decided against it for now because the TrueNAS app talks to a cluster IP and putting a sidecar proxy in the way is more moving parts than two lines of uBO config deserve. If I end up watching this thing on a Smart TV I’ll revisit.
The whole exercise took about ten minutes once I stopped trying to make youtube.com filter lists work on a page that has none of youtube.com’s markup. My subs feed looks like 2018 again.