DEV Community

Delta Tools
Delta Tools

Posted on

How to Get Notified When a Substack Publication Posts Something New

TL;DR: Every Substack publication has a hidden RSS feed at publicationname.substack.com/feed. You can watch it with an RSS reader, poll it with a 20-line Python script, or — if you want alerts without running infrastructure — use a scheduled monitor like our Substack New-Post Monitor. Below are all three methods, working code included.


I follow about a dozen Substack publications. For months my system was "remember to check them," which is to say I missed half of everything. Substack has email subscriptions, but I didn't want a dozen newsletters clogging my inbox — I wanted a ping only when something new went live, routed where I actually look.

There are three solid ways to do this. They go from simplest to most automated.

Method 1: The hidden RSS feed + a reader (2 minutes, free)

This is the thing most people don't know: every Substack publication exposes an RSS feed at:

https://<publication>.substack.com/feed
Enter fullscreen mode Exit fullscreen mode

So if you follow stratechery.substack.com, the feed is https://stratechery.substack.com/feed. It contains the latest posts with titles, links, and timestamps. It just works — no API key, no scraping.

Point any RSS reader at it (Feedly, Inoreader, NetNewsWire, even an old-school reader). You'll see new posts alongside everything else you follow. Zero code, zero cost.

Downside: it's pull, not push. You see new posts when you open the reader, not the moment they go live. If "the moment it happens" matters — job alerts, deal alerts, time-sensitive analysis — keep reading.

Method 2: Poll the feed with a script (20 lines of Python)

If you want actual notifications (Slack, Discord, email, SMS), poll the feed on a schedule and diff against what you've already seen. Here's the whole thing:

import feedparser, json, os, time

FEED_URL = "https://example.substack.com/feed"
SEEN_FILE = "seen_ids.json"

seen = set(json.load(open(SEEN_FILE))) if os.path.exists(SEEN_FILE) else set()

feed = feedparser.parse(FEED_URL)
new_posts = [e for e in feed.entries if e.id not in seen]

for post in new_posts:
    print(f"NEW: {post.title} — {post.link}")
    # send_to_slack(f"New post: {post.title}\n{post.link}")

seen.update(e.id for e in feed.entries)
json.dump(sorted(seen), open(SEEN_FILE, "w"))
Enter fullscreen mode Exit fullscreen mode

Run it on a cron every 15 minutes. The seen_ids.json file is the entire "database" — and it's also the entire point. Dedup is the whole product. Without remembering what you've already seen, every poll re-alerts on the same posts. With it, you get exactly one alert per new post.

This works fine for one or two publications on a machine that's always on (a Raspberry Pi, a cheap VPS, or just your laptop if you don't mind it sleeping through alerts).

Downsides at scale: run it for ten publications and you're managing ten cron jobs and ten state files. Move machines and the state file doesn't come with you — hello, duplicate alerts for everything. And if the script crashes between "detect" and "save state," you either miss posts or double-alert. I learned all of this the annoying way, which is why method 3 exists.

Method 3: A scheduled monitor that handles the boring parts (no infrastructure)

This is what I ended up building: a small Apify actor that watches a Substack publication and reports new posts. You give it the publication URL and a schedule. New posts land in the output dataset, which you can wire to Slack, email, or webhooks through Apify's integrations — no cron jobs or state files to babysit. A check that finds nothing new costs a fraction of a cent.

The Substack New-Post Monitor is the one I run myself. One job per tool, priced per result — a scheduled check that finds nothing new costs almost nothing.

I'm not going to pretend it's the only option. If you like running your own infra, method 2 is genuinely fine and the code above is yours to keep. The actor exists for people who'd rather not babysit cron jobs and state files.

Which method should you pick?

  • Just want to read new posts in one place? Method 1. RSS reader, done in two minutes.
  • Want push alerts and don't mind a tiny bit of ops? Method 2. The script above, a cron job, somewhere always-on.
  • Want alerts with zero infrastructure? Method 3. Set it once, get pinged.

FAQ

Does this work for paid Substack publications?
The public /feed only includes free posts. Paid-only content behind the paywall isn't in the public feed — for that you'd need to be subscribed and logged in, which is a different (harder) problem.

How fast are the alerts?
Method 1 is whenever you open your reader. Method 2 is your cron interval (15 minutes is polite; don't hammer it every 60 seconds). Method 3 runs on whatever schedule you set.

Will Substack block polling?
At reasonable intervals (every 10–15 minutes), no. It's a standard RSS feed designed to be polled. Don't poll every minute from five IPs — that's how you get rate-limited anywhere.

Can I watch multiple publications at once?
Method 1: add multiple feeds to the reader. Method 2: loop over a list of feed URLs (one state file per publication, or namespace the IDs). Method 3: the actor's input takes a list of publications in a single run.

What about Substack's own email notifications?
They work, but they're all-or-nothing per publication and they land in your inbox mixed with everything else. These methods give you routing control — Slack, Discord, webhook, SMS — and let you watch publications without subscribing to their emails.

Top comments (0)