Atom and how readers consume feeds

Where Atom differs from RSS, how feed readers poll with conditional requests, and what that means for your server.

Atom versus RSS 2.0

ConcernRSS 2.0Atom 1.0
Root element<rss version="2.0"><feed xmlns="http://www.w3.org/2005/Atom">
Spec statusFrozen, informal but universalIETF standards track (RFC 4287)
Item elementitementry
Identifierguidid, required, an IRI
DatesRFC 822 stringsISO 8601 / RFC 3339
Content modeldescription with escaped HTMLcontent with type of text, html or xhtml
NamespacesOptional extensions are informalBuilt in from the start
UpdatesNot modelledupdated is required on feed and entry
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Example Dev Blog</title>
  <id>https://example.com/</id>
  <updated>2026-09-18T09:00:00Z</updated>
  <link href="https://example.com/feed.atom" rel="self"/>
  <link href="https://example.com/"/>

  <entry>
    <title>Understanding HTTP caching</title>
    <id>https://example.com/posts/http-caching</id>
    <updated>2026-09-17T12:00:00Z</updated>
    <link href="https://example.com/posts/http-caching"/>
    <summary>Freshness, validators and the 304 response.</summary>
    <content type="html">&lt;p&gt;The full article, escaped.&lt;/p&gt;</content>
  </entry>
</feed>

Atom is stricter and better specified; RSS 2.0 is simpler and better supported. Serving both is cheap — many sites publish feed.xml and feed.atom from the same data.

How a reader actually polls

  1. The reader fetches the feed URL on a schedule, typically every 15 minutes to a few hours.
  2. It sends If-None-Match and If-Modified-Since from the last fetch.
  3. A 304 Not Modified ends the exchange with no body — the common case.
  4. On a 200 it parses the XML, then diffs by guid or id to find unseen items.
  5. New items are stored and shown; missing items may be remembered so a later reappearance is not treated as new.
  6. Failures are backed off: repeated errors lengthen the polling interval or disable the feed.
# emulate a reader: fetch, remember the validator, then revalidate
curl -sSI https://example.com/feed.xml | grep -iE 'etag|last-modified'

curl -sS -o /dev/null -w '%{http_code}\n' \
  -H 'If-None-Match: "feed-2026-09-18-01"' \
  https://example.com/feed.xml          # expect 304

# aggregate feeds are frequently rate limited - honour Retry-After
curl -sSI https://example.com/feed.xml | grep -i retry-after
⚠️
A feed is polled by every subscriber, so an uncached feed endpoint is a self-inflicted load test. Serve it from a CDN or a static file, and return a 304 or a short max-age rather than re-rendering the document on every request.

What this means for publishers

  • Feeds are pull-based, so publish timing is a courtesy, not a guarantee: readers decide when to ask.
  • WebSub (formerly PubSubHubbub) flips the model — the publisher pushes a notification and the hub tells subscribers to fetch immediately.
  • Track subscription counts through feed analytics or a redirect on item/link, never by cloaking the feed.
  • Keep the feed URL permanent and redirect it if the path changes; a broken feed is invisible in analytics and silent in support.
  • Offer a clean article URL in link; tracking parameters in feeds look like cloaking to some aggregators.

The durable insight is that feed readers are just disciplined HTTP clients: they cache, revalidate, respect rate limits and diff by stable identifiers. Feeds fail more often from broken identifiers and invalid XML than from any gap in the format itself.

FAQ

RSS or Atom for a new site?
Publish RSS 2.0 as the default because support is universal, and add Atom if your audience or tooling prefers a standards-track format. Generate both from one data source.
Why does my feed show old items as new?
The guid changed. Any change to the identifier — including a URL that gained a query string or moved to HTTPS — makes readers treat the item as unpublished content.

Generating a valid feed The RSS 2.0 feed format

Last refreshed 2026-09-18.