# Changelog of RSS & Atom Feed Reader: Feed Scraper & Monitor, RSS to JSON (`humble-echidna/rss-feed-reader`) Actor

- **URL**: https://apify.com/humble-echidna/rss-feed-reader/changelog.md
- **Full Actor documentation**: https://apify.com/humble-echidna/rss-feed-reader.md

## Changelog

Versions follow MAJOR.MINOR.PATCH (`src/version.py`); Apify shows MAJOR.MINOR from `.actor/actor.json`.
Every run logs its version and records it in the `RUN_STATS` key-value record.

### 1.0.7 (2026-10-16)

- A run that returns nothing (every input bad, private, blocked or unreachable, or an empty input) now ends
  SUCCEEDED with an empty dataset and the reason as its status message and in the log, instead of FAILED. Only an
  unexpected error still fails the run. `RUN_STATS` keeps the reason as before.
- No change to output fields or price.

### 1.0.6 (2026-10-03)

- A run no longer fails when the store it remembers earlier runs in can't be opened (403: the account already has
  a store of that name that this actor didn't create). It falls back to `humble-echidna-<name>`, and if that is
  refused too it runs without memory for that run. Users' existing memory is untouched: the usual name is tried first.

### 1.0.5 (2026-10-01)

- **Waits out longer `Retry-After` answers:** when a site or API asks it to wait before retrying, it now waits up
  to 90 seconds (was 30), once per site, with at most 3 minutes of such long waits per run; a longer wait, or a
  site that asks again after it was waited out, is reported with the reason instead of stalling the run.
- **Narrower AI opt-out rule:** a page is skipped as opting out of AI use only when the site's robots.txt
  disallows it for a general AI token (Google-Extended, Applebot-Extended, CCBot, or OpenAI's, Anthropic's or
  Perplexity's crawlers and user fetchers). Blocking only one company's crawler (Bytespider, Meta-ExternalAgent,
  Amazonbot, Diffbot, Omgilibot, cohere-ai) no longer counts: GitHub and Notion pages, for two, are read now.
- No change to input, output or price.

### 1.0.4 (2026-09-28)

- 2 ready-to-run examples published on Apify Store and linked from the README.

### 1.0.3 (2026-09-28)

- Cheaper on paid Apify plans: $0.90 per 1,000 items on Starter, $0.80 on Scale and $0.70 on Business ($1.00 on the Free plan).

### 1.0.2 (2026-09-25)

- Input field descriptions rewritten for AI agents (Apify's MCP server shows agents only the description, not the
  form): each now states its default, its allowed range and how it combines with other fields. No change to field
  names, types, defaults or behaviour.

### 1.0.1 (2026-09-24)

- Internal: feed parsing, discovery and rendering now live in the shared `mms_feeds` package, shared with the new article-extractor actor. No change in behaviour or output.

### 1.0.0 (2026-09-24)

- Also honours robots.txt opt-outs aimed at AI crawlers (GPTBot, CCBot, ClaudeBot, ...), like page-to-markdown.
  First release.
- Reads RSS 2.0 / 0.9x, RSS 1.0 (RDF), Atom 1.0 and JSON Feed 1.x from the URLs you give it; a website URL works
  when its page advertises a feed with `<link rel="alternate">` (comment feeds last).
- One row per item: title, link, published/updated in ISO 8601 UTC, author name (email addresses removed),
  summary and full text as plain text, optional Markdown, categories, enclosures, guid, feed title/URL/format.
- Filters: keywords (title, summary, full text, categories) and "published since" (date, date-time or a period).
- "Only new items": remembered per feed and per filter combination in the user's `rss-feed-reader-seen` store;
  items are marked seen only after they're written to the dataset, and a failed or empty fetch forgets nothing.
- The same feed given twice in one run is read and charged once.
- XML is parsed with defusedxml (no entity expansion, no external entities). Feeds up to 10 MB, 5,000 items per
  feed, 100,000 characters per text field.
- Fetching through the shared client: robots.txt and Crawl-delay honoured, public addresses on ports 80/443 only.
- Charged per item returned, through Apify's standard `apify-default-dataset-item` event.
- "Max results per run" input, and the maximum cost per run is honoured: once either is covered, feeds still
  being fetched are cancelled and the rest are skipped (listed as `queriesSkipped` in `RUN_STATS`).
- Failure isolation: a failing feed only affects itself.
