Skip to content

RSS Feeds Still Matter

RSS feeds are a dying breed. They bring me back to a simpler time of the Web 2.0 internet - before everything was so commercialized and filled with AI slop.1 In those days, before modern social media giants controlled the vast majority of web traffic, the world-wide-web felt more whimsical and personal. RSS enabled you to retrieve other sites' content and bring them into your own reader, almost like an email inbox of articles.

What RSS Is

RSS (Really Simple Syndication) is a web technology that allows websites to structure their content in a standardized format that feed readers accept.

If you see this handy logo (RSS logo) on a website that you encounter when surfin' the web, you can natively import the feed into your reader app. Simply copy the feed URL that looks like this:

https://feeds.npr.org/1001/rss.xml

then paste it in your reader of choice and voilĂ  - you've got copies of the articles in a reader format ready for your consumption.

NPR feed is FreshRSS

Fun fact - the standard way to distribute a podcast is actually based on RSS. If I go to the RSS feed for the Vergecast in my browser, I can see the raw XML of what a podcast app actually receives.

RSS feed XML of the Vergecast

Clearly RSS is still a backbone of how the internet functions - but once upon a time it was a nerdy consumer facing technology. What caused this shift?

Why RSS Died

Business models matter on the internet just as much as they matter in the "real world." Just like I talked about in my article about recipes and SEO, the primary way web publications make money is advertising or referrals. Offering an RSS feed of your full content immediately cuts off one of those revenue sources. If you can get the complete article without loading any annoying ads, it's a preferable user experience, but utterly unsustainable assuming the publication pays the writer who spends time producing the article.

Just like modern day venture capital throws money at anything AI, once upon a time "New Media" was the new hotness. Early on, during the "build fast and find a way to make money later" era, web publications would gladly give away their content freely to get more readership. Later, during the "turn this money furnace into a sustainable company" era - aka "enshittification" - these feeds were stripped back into just a short summary with a link to the ad-infested article.

RSS feeds feel like a relic of a bygone internet era. Google killed the most popular feed reader, Google Reader all the way back in 2013. CNN's RSS feeds unceremoniously stopped working in mid-2023. Centralization of the internet means that platforms like Substack or email newsletters are the predominant way of accomplishing RSS functionality.

Social media also changed the primary way that consumers used the internet. Feed readers are inherently a personal medium - sharing articles via Facebook, Twitter, etc is a far more social experience. The tradeoff of being siloed in a single social media site with infinite content versus interacting with the World Wide Web was one most consumers were willing to make.

How I Use RSS

In the modern social-media driven algorithmic world, I see value in self-hosting something to help be more intentional about my media consumption. Rather than have the Google News feed decide what I'll read, keeping a curated list of RSS feeds in a reader takes the power back. I'm doing things on my own terms - plus, it's another excuse for me to self-host something!

I am not yet an RSS power user but I have started an attempt to roll out a feed reader for myself. Back in the day, I myself used to be a big Google Reader fan. In current day, I've started to use FreshRSS as my self-hosted feed reader of choice. It's a simple to use feed reader that doesn't look too bad, either!

Dashboard of FreshRSS

I run most of my services using Docker, so it was straightforward to deploy. I did so using this Docker Compose:

freshrss-db:
  image: postgres:12-alpine
  container_name: freshrss-db
  hostname: freshrss-db
  restart: unless-stopped
  volumes:
    - /home/user/Containers/FreshRSS/db:/var/lib/postgresql/data
  environment:
    POSTGRES_USER: freshrss
    POSTGRES_PASSWORD: sample_password
    POSTGRES_DB: freshrss
  dns:
    - "1.1.1.1"
freshrss-app:
  image: freshrss/freshrss:latest
  container_name: freshrss-app
  hostname: freshrss-app
  restart: unless-stopped
  dns:
  - "1.1.1.1"
  ports:
    - "80:80"
  depends_on:
    - freshrss-db
  volumes:
    - /home/user/Containers/FreshRSS/data:/var/www/FreshRSS/data
    - /home/user/Containers/FreshRSS/extensions:/var/www/FreshRSS/extensions
  environment:
    CRON_MIN: '*/20'
    TZ: America/New_York

After going through the initial setup wizard, FreshRSS was a blank slate ready for some feeds.

FreshRSS blank slate

Blank FreshRSS interface

As a Verge subscriber, squidward dabbing|42x40 I was able to import the full-text of articles from the Verge website. That also means that the Verge was being compensated to provide me this content.

FreshRSS import of the Verge website

FreshRSS including articles from the Verge

This was great for one specific website, but what about other sites that have their content freely available (i.e., no paywall) but had their RSS feed truncated?2

A tool called Full-TextRSS from fivefilters.org accepts a truncated RSS feed, goes to the article, parses it, and returns a full text RSS article.

Here's another docker container install to get this new shiny up and running:

1
2
3
4
5
6
7
8
9
fullfeedrss:
  container_name: fullfeedrss
  image: "heussd/fivefilters-full-text-rss:latest"
  environment:
    - FTR_ADMIN_PASSWORD=samplepassword
  volumes:
    -  /home/user/Containers/rss-cache:/var/www/html/cache
  ports:
    - "80:80"

I was able to go to the fullfeedrss container where it let me paste in a feed URL:

Full text RSS

Using the same NPR feed from earlier, I pasted it in and let the container do its magic. The new feed https://feed.vpn.gran.to/makefulltextfeed.php?url=sec%3A%2F%2Ffeeds.npr.org%2F1001%2Frss.xml&max=200&links=preserve&exc=&submit=Create+Feed&parser=html5php included the complete article version of the articles, not just the summaries.

NPR FreshRSS Example

FreshRSS including full article from NPR.org

I hope to continue curating my RSS feeds, keeping a better relationship with scrolling through the news. Even though RSS feed readers have a familiar design to email inboxes, I don't want to have the expectation to read every article. The "mark all as read" button is my friend. The goal is to have the option to read media in this environment, not have another chore to clear out a notification number.

After my experience with the modern web and the implementation of RSS, it made me realize the value of having an RSS feed for this blog.

Getting RSS Back

When I switched my blog from WordPress to Mkdocs Material, I lost the native support for RSS. WordPress provided some of the creature comforts of the open web that something designed for code documentation needs some customization to get back. Luckily, Mkdocs Material has a solution to create RSS feeds for the blog plugin using the mkdocs-rss-plugin package. I simply had to install it to my blog site:

pip install mkdocs-rss-plugin

I had a few customizations I had to modify in mkdocs.yml - the main configuration file for this blog.

- rss:
  match_path: blog/posts/.*
  use_material_blog: true
  abstract_chars_count: -1
  date_from_meta:
    as_creation: date
  categories:
    - categories
    - tags
  use_git: false 
- blog:
  post_url_format: "{date}/{slug}"

That abstract_chars_count being set to -1 ensures that my RSS feed is the full text article - no need for fancy containers to parse the full text here. I also have no intention of making money from my personal website, so there's no risk for me there. I also specifically had to disable the RSS plugin's git integration due to deploying to Cloudflare pages - I got this error message before disabling it:

Error Message
Date Message
23:55:21.862 File "/opt/buildhome/.asdf/installs/python/3.11.5/lib/python3.11/site-packages/mkdocs_rss_plugin/plugin.py", line 138, in on_config
23:55:21.862 self.util = Util(
23:55:21.862 ^^^^^
23:55:21.862 File "/opt/buildhome/.asdf/installs/python/3.11.5/lib/python3.11/site-packages/mkdocs_rss_plugin/util.py", line 125, in init
23:55:21.862 CiHandler(git_repo.git).raise_ci_warnings()
23:55:21.863 File "/opt/buildhome/.asdf/installs/python/3.11.5/lib/python3.11/site-packages/mkdocs_rss_plugin/git_manager/ci.py", line 45, in raise_ci_warnings
23:55:21.863 n_commits = self.commit_count()
23:55:21.863 ^^^^^^^^^^^^^^^^^^^
23:55:21.863 File "/opt/buildhome/.asdf/installs/python/3.11.5/lib/python3.11/site-packages/mkdocs_rss_plugin/git_manager/ci.py", line 104, in commit_count
23:55:21.863 refs = [x.split()[0] for x in refs]
23:55:21.863 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This exciting gobbledygook means that it was unable to find a valid Git repo - even though I write this blog in a git repo. However, this repository is not initialized in the Cloudflare environment that deploys the site, so I needed to ensure that use_git: false was set or else the build would fail.

Once I successfully set up the plugin, it automatically set up an RSS feed for my site at https://grantmclravy.com/feed_rss_created.xml and set up the necessary headers in the <head> element of my blog.

RSS link highlighted in the head tag

From FreshRSS, I went to go add this new feed:

Image of feed setup in FreshRSS

Second image of feed setup in FreshRSS

There was a button to check the validity of the feed, and several things failed the feed validation:

Failure validating feed

The feed I was generating wasn't a valid feed for three reasons:

  1. Image URL was blank - returning as None
  2. The author field did not include an email address as required
  3. There was no "channel element description"

For the image URL, I had to add that to my RSS configuration in my mkdocs.yml:

rss: 
  [...]
  use_git: false
  image: https://grantmclravy.com/images/Headshot.jpg 

Author field just required me to add an email to my .authors.yml metadata:

authors:
  grant:
    name: Grant McLravy
    description: Grant McLravy
    avatar: https://gravatar.com/avatar/1e12aebdf63d7b9c14d1ca7d06282456770fda7a9f2e3dffd8d18669d9c5ae4a?size=256
    slug: grant
    url: https://grantmclravy.com/
    email: [email protected]

Setting up the "channel element description" just required updating mkdocs.yml with a description.

site_description: Grant McLravy's Personal Blog

After fixing these things, my feed validated. I was able to add it to FreshRSS:

My feed in FreshRSS

It successfully pulled all of my posts into my feed reader. If you want to do the same, add this feed and you will get one or two posts a year to read in your feedbox.

https://grantmclravy.com/feed_rss_created.xml

RSS is not as culturally relevant in the nerd sphere as it was 10-15 years ago, but it's still a powerful tool for decentralized content consumption. Self-hosting enables keeping these technologies alive even when tech megacorps deem them not worth supporting. Plus, keeping my website custom(ish) means I can be an example of the things I care about.


  1. Side note - all of these blog posts are genuine handwritten slop. I'll always note things that are AI generated - I've updated a few of my older posts with some notes about where I used AI. For example, I used ChatGPT to generate my recipe JSON-LD for my recipe post but the recipe was all me. 

  2. Side note - there should be a separate discussion about the ethics of adblocking. Reference Linus's controversial Adblock equals piracy take