If a site IP-blocks your cloud egress but still serves RSS to Google, you can put FeedBurner between them and change zero lines of parsing code. I measured this end to end against a site that login-walls datacenter IPs. It works, the fidelity is far better than the folklore suggests, and the real cost is freshness, not correctness.
This is a bridge, not an architecture. But it costs nothing, needs no vendor account, and needs no API approval, which makes it the cheapest thing to have validated before you need it.
The setup
A large site began classifying cloud/datacenter egress and serving those IPs a 302 to /login/ instead of feed content. feedparser follows the 302 silently and chokes on the login HTML, so the symptom is a bozo parse error rather than an HTTP error. Residential proxies work until they do not (the exit pools get flagged too, and in my case the classification later inverted so the proxy became the only blocked path).
FeedBurner takes a source feed URL, polls it from Google's infrastructure, and republishes at https://feeds.feedburner.com/<name>. Your fetch becomes an ordinary read of a Google host that no classifier is looking at. It is still alive in 2026: Google put it in maintenance mode in July 2021 but explicitly kept feed creation working. See https://support.google.com/feedburner/answer/10483501.
Surprise 1: it does not rewrite your links
The reason I nearly skipped this option is the widely-remembered FeedBurner behavior of wrapping every entry link in a feedproxy.google.com redirect and adding feedburner:origLink elements. That would break permalink-based dedupe and any liveness checking.
It does not do that anymore, at least not for a plain burn with no link-tracking options enabled. Measured on a burned feed:
import re, feedparser
d = feedparser.parse(body)
# bozo=False, version='atom10', 25 entries
assert not any('feedproxy' in e.link or 'feedburner' in e.link for e in d.entries)
assert b'feedburner' not in body # no namespace at all
assert body.count(b'origLink') == 0 # no link rewriting feedparser verdict | bozo=False, version='atom10' |
Entry link host | the origin site, 25/25, unwrapped |
feedburner:origLink elements | 0 |
| FeedBurner namespace in document | absent |
title / author / id / published / content / tags | all preserved |
Trailing footer hrefs inside content | preserved |
That last row matters more than it looks. Several feed sources encode structural information in the anchor tags at the end of each entry's content, and downstream classifiers depend on it. FeedBurner passed it through.
The practical consequence: pointing a source row at a burned URL required no parser changes. It is the origin's own Atom, re-served.
Surprise 2: it is reachable from exactly the egress that was blocked
Probed from the cloud platform's shared outbound pool, the same egress the origin was 302ing:
3/3 HTTP 200, content-type: text/xml, body opens with <?xml, 25 <entry> elements
cache-control: no-cache, no-store, max-age=0, must-revalidate (no `age` header)Identical results with a descriptive bot User-Agent and with browser-impersonation headers, so FeedBurner does not fingerprint you. The no-store and missing age header mean you read FeedBurner's own stored copy, not a CDN edge.
The real cost: a freshness lag you cannot drive
This is the part to plan around.
FeedBurner feed <updated> | 18:53:05Z |
Origin feed <updated>, same moment | 19:49:02Z |
| Lag | 56 minutes |
| Entry id overlap | 18 of 25 |
| Entries the origin had that FeedBurner did not | 7 |
Responses were byte-identical across three rapid fetches and across a 17-minute gap, so FeedBurner refreshes on its own schedule and polling harder does not help.
The trap: entry-window drain on high-volume feeds
The lag alone is harmless. The lag combined with a small entry window is not, and it fails silently.
Burn a /new-style firehose without a limit parameter in the source URL and you get the origin's default page size (25 here, not 100). Then do the arithmetic that nobody does:
observed post rate ~7.5 entries/hour
served window 25 entries
window drain time 25 / 7.5 = ~3.3 hours
your poll interval 6 hours
=> entries published between polls that fall out of the window are never seenThat quietly dropped roughly 40% of entries. Nothing errors; you just ingest less. Two rules follow:
- Put the
limitparameter in the burned source URL, not in the URL you fetch. FeedBurner serves whatever the source gave it. - Check
window_size / post_rate > poll_intervalbefore trusting a burn on any busy feed. A day-scoped "top" listing is fine at 25 entries because it barely moves; a/newfirehose is not.
Validate freshness, not reachability
The failure mode that will actually bite you is FeedBurner quietly freezing because the origin started blocking Google. A frozen feed is indistinguishable from a healthy one on a single fetch: 200, valid XML, plausible entries.
So the acceptance test is not one request. It is:
- HTTP 200, and
- body starts with
<?xmlor contains<feed xmlns(never trust the status alone; feed hosts serve error pages with 200), and - a non-trivial entry count, and
<updated>advances and entry ids turn over between two checks a day apart.
Only the last one distinguishes "working" from "frozen against a cached copy."
When not to reach for this
- Setup is manual and stays manual. FeedBurner's management API was retired; every feed is a hand burn, forever.
- It is still RSS. It recovers none of the fields the origin's RSS omits (scores, comment counts, flair). If you were considering an official API partly for richer data, this does not substitute.
- It is a maintenance-mode product with no roadmap, which is the exact profile of something that gets a sunset notice.
- Posture. If the origin is serving your egress a
Disallow: /robots.txt, routing around it through an intermediary is the same move as a proxy in nicer clothes. Know that you are making that choice.
Paid siblings exist with real APIs over commercial crawlers, but they reintroduce a monthly vendor: Inoreader gates API access behind a Pro plan for anything other than a public client (https://www.inoreader.com/developers/), and Feedly's is similarly business-tier. Self-hosted RSSHub or RSS-Bridge does not help at all, since it fetches the origin from wherever you run it and inherits your egress problem unchanged.