DEV Community

Usama Ejaz
Usama Ejaz

Posted on Originally published at justblogged.com

Why New Blog Posts Reach Feed Readers Hours Late, and Which Platforms Send a WebSub Hub

A new post shows up in a feed reader only when the reader next fetches your feed. Most readers fetch on a schedule, and for a small blog that schedule is slow. Feedly's free plan checks a feed anywhere from every 30 minutes to once a day.

The way around it is a WebSub hub. Your feed names a hub, your platform pings it when you publish, and readers subscribed to the hub get the post when the hub pushes it. On October 19, 2026 I fetched one feed from each of ten blogging platforms to see which ones declare a hub. Three did.

How often readers actually check

These come from each reader's own docs as of October 19, 2026.

Reader How often it polls Source
Feedly Basic 30 minutes to 1 day, depending on how popular the site is and how often it publishes Feedly help
Feedly Pro 15 minutes to 1 hour same
Feedly Pro+ and Enterprise As often as every 7 minutes same
Inoreader Active feeds every 30 minutes to a few hours; few subscribers at most hourly; quiet for a month about daily Inoreader feed fetcher
Miniflux (self-hosted) Round-robin with a 60-minute minimum by default; the optional entry_frequency scheduler adapts from 5 minutes to 24 hours based on the last week Miniflux configuration

The popularity factor is what hurts a personal blog. A handful of subscribers on free accounts puts you at the slow end of every schedule, and publishing once a week makes you look like a feed that rarely changes.

Both Feedly and Inoreader say what skips the schedule. Feedly says sites using "the PuSH protocol" show up "in near real-time." Inoreader says that when it finds a hub it "receives new items as soon as you publish them" and falls back to polling every few hours.

What a hub changes

WebSub is the W3C Recommendation that grew out of PubSubHubbub, the "PuSH" Feedly mentions. Three parties:

  • Your feed advertises a hub with rel="hub" and its own address with rel="self".
  • A reader that supports WebSub subscribes to the hub for that feed.
  • When you publish, your platform tells the hub, and the hub fetches the feed and pushes it to every subscriber.

The spec leaves one step open: "The specific mechanism for the publisher to inform the hub is left unspecified." In practice the public hubs accept the same thing, a form POST with hub.mode=publish and hub.url set to your feed. That's documented on Google's public hub, which anyone can use without an account.

It doesn't help readers that never look for a hub, and it doesn't stop polling. It removes the wait for the readers that support it.

Which platforms declare one

One public feed per platform. I looked for rel="hub" in the XML and in response headers. I also sent each response's ETag and Last-Modified back as If-None-Match and If-Modified-Since, which is what Inoreader says its fetcher does, to see if the server answers an unchanged feed with 304 Not Modified. A 304 doesn't speed up delivery, but without it every poll downloads the whole file.

Platform (feed checked) Hub 304 on an unchanged feed
Medium (medium.com/feed/@ev) Yes, http://medium.superfeedr.com No validators sent
WordPress.com (wordpress.com/blog/feed/) Yes, https://wordpress.com/blog/?pushpress=hub Yes
Blogger (blog.chromium.org/feeds/posts/default) Yes, http://pubsubhubbub.appspot.com/ No, sent Last-Modified but answered the replay with 200
Self-hosted WordPress 7.2 alpha (wordpress.org/news/feed/) No Yes
Ghost 6.71 (404media.co/rss/) No Yes
Substack (lennysnewsletter.com/feed) No Yes
Bear (herman.bearblog.dev/feed/) No Yes
DEV (dev.to/feed/ben) No Yes
Hashnode (townhall.hashnode.com/rss.xml) No No validators sent
JustBlogged (justblogged.com/blog/rss.xml) No No validators sent

One feed per platform is a sample. A self-hosted WordPress or Ghost site can behave differently because of plugins, themes or the cache in front of it. Several Blogger blogs I tried redirected their feed to FeedBurner, which serves its own copy, so check the URL your readers are actually subscribed to.

The last row is mine. I build JustBlogged, and its own blog feed carries every full post, 594,833 bytes this morning, with no hub, no ETag and no Last-Modified. So readers of that blog wait for their reader's schedule, and every poll downloads the whole file.

Check your own feed

First, does it declare a hub? Either as a link in the XML or as an HTTP Link header, which the spec says subscribers check first.

FEED=https://example.com/feed.xml
curl -sSL "$FEED" | grep -io '<[a-z:]*link[^>]*rel=.hub.[^>]*>'
curl -sSIL "$FEED" | grep -i '^link:.*hub'
Enter fullscreen mode Exit fullscreen mode

Second, does it answer 304 when nothing changed? This sends back both validators the way a reader would:

H=$(curl -sS -D - -o /dev/null "$FEED")
ETAG=$(echo "$H" | grep -i '^etag:' | cut -d' ' -f2- | tr -d '\r')
LM=$(echo "$H" | grep -i '^last-modified:' | cut -d' ' -f2- | tr -d '\r')
curl -sS -o /dev/null -w '%{http_code}\n' \
  -H "If-None-Match: $ETAG" -H "If-Modified-Since: $LM" "$FEED"
Enter fullscreen mode Exit fullscreen mode

Send both headers. WordPress.com answered 304 to If-Modified-Since but 200 to its own ETag alone, so a one-header test can report a failure real readers never hit.

While the headers are open, look at cache-control and age. The Bear feed came back with s-maxage=43200 and a Cloudflare cache hit, which lets the edge keep a copy for up to 12 hours. I didn't check whether Bear purges it on publish. On any host, if the feed is cached at a CDN and not purged on publish, the new post isn't in the feed readers fetch, and no hub fixes that. Fetch your feed right after publishing and confirm the item is there.

Adding a hub yourself

Self-hosted WordPress: the WebSub plugin (4.0.1, 100,000+ active installs as of October 2026) adds hub links to your feeds and pings hubs on publish and update. It uses Google's hub, Superfeedr and WebSubHub by default.

Static site generator: two edits. Add the hub link next to rel="self" in your RSS channel, with the Atom namespace on <rss>:

<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <atom:link rel="self" type="application/rss+xml" href="https://example.com/feed.xml"/>
    <atom:link rel="hub" href="https://pubsubhubbub.appspot.com/"/>
    ...
Enter fullscreen mode Exit fullscreen mode

Then ping at the end of your deploy, after the new feed is live:

curl -sS -o /dev/null -w '%{http_code}\n' -X POST https://pubsubhubbub.appspot.com/ \
  -d hub.mode=publish \
  --data-urlencode hub.url=https://example.com/feed.xml
Enter fullscreen mode Exit fullscreen mode

A 204 means the hub accepted the ping, not that anyone got notified. I sent that request for a feed with no hub link at all and Google's hub still answered 204. Delivery only happens for readers that found the hub in your feed and subscribed, so the link has to be live first. And rel="self" has to be the exact URL subscribers use, because that's the topic the hub tracks.

On a hosted platform without a hub there's no setting to flip. Your subscribers' readers poll on their own schedule

Top comments (0)