# RSS & Atom Date-Window Export (`sapph1re/rss-atom-date-window-export`) Actor

Export supplied public RSS and Atom feeds with exact UTC date windows, stable feed-scoped IDs, item-only datasets and separate feed outcomes.

- **URL**: https://apify.com/sapph1re/rss-atom-date-window-export.md
- **Developed by:** [Roman V](https://apify.com/sapph1re) (community)
- **Stats:** 1 total users, 1 monthly users, 80.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.00 / 1,000 exported feed items

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## RSS & Atom Date-Window Export

Turn a list of public RSS 2.0 or Atom 1.0 feed URLs into a dataset of useful items for a reporting interval. Publication and update dates stay separate. Each run also saves per-feed outcomes, exclusion counts and a delivery receipt in `OUTPUT`.

The Actor reads the items currently present in each supplied feed response. It cannot recover an older article that the publisher has removed from the feed. It does not search Google News, discover feeds, crawl article links, follow feed pagination, fetch enclosures or maintain a cross-run news baseline.

### Start with a small example

An empty object uses the RSS Advisory Board's public five-item sample. These are sample NASA stories from 2023, not current news. Default selection is at most five items and a $0.005 item-charge ceiling.

```json
{}
```

To select the sample's July 20 and 21 publication dates:

```json
{
  "feedUrls": ["https://www.rssboard.org/files/sample-rss-2.xml"],
  "publishedFrom": "2023-07-20T00:00:00Z",
  "publishedBefore": "2023-07-22T00:00:00Z",
  "dateField": "published",
  "maxItems": 5,
  "maxChargeUsd": 0.005
}
```

Use the same JSON in Console or the Actor API request body. The package contains `examples/defaults.json`, `examples/exact-window.json` and `examples/multi-feed.json`. The latter supplies both the sample feed and NASA's public feed, with two items per feed and four overall.

### Date and identity rules

`publishedFrom` includes the specified instant. `publishedBefore` excludes it. Both accept RFC 3339 timestamps with `Z` or a numeric offset, normalized to UTC. The field names remain the same when `dateField` is `updated`. Feed order is preserved, and an old item does not stop scanning the rest of a feed.

RSS uses native `pubDate` for publication and has no native update timestamp. Atom uses `published` and `updated` independently. Missing, invalid, timezone-free and unsupported dates stay null. Channel dates, update dates and fetch time never substitute for an absent publication date. RSS extension dates such as Dublin Core are outside this version's contract.

With a window, an absent selected date is excluded and counted by default. `includeUndated: true` returns it with `window_membership: UNKNOWN_DATE`. With no window, undated items are included and labeled `NOT_FILTERED`. Present matching dates are labeled `IN_WINDOW`.

A `record_id` hashes the normalized original input feed URL and the item's native RSS GUID or Atom ID. Redirects do not change that feed identity. Different feeds retain identical GUID strings as separate records; different IDs sharing a URL also remain separate. IDs are opaque, case-sensitive strings. An item without a native ID uses a hash of its XML element excluding surrounding feed whitespace. That fallback can change when item content changes and carries a warning. It is not a cross-run monitoring guarantee.

Repeated identities within one feed keep the first occurrence in source order. A conflicting later occurrence adds `CONFLICTING_DUPLICATE_FIRST_WINS` to the retained item and increments a feed counter. Filtering applies to the retained first occurrence. Input URL query parameters are preserved; normalized duplicate feed inputs are fetched once.

### Output

Each dataset row is an item, with these fields:

| Fields | Meaning |
| --- | --- |
| `record_id`, `identity_basis`, `source_item_id` | Feed-scoped identity and its source |
| `feed_url`, `final_feed_url` | Input feed and final feed after allowed redirects |
| `item_url`, `title`, `summary` | Supplied metadata, with safe text extraction for summaries |
| `published_raw`, `published`, `updated_raw`, `updated` | Source dates and parsed UTC values, independently nullable |
| `date_basis`, `selected_date`, `window_membership` | Selection evidence |
| `tags`, `enclosures`, `warnings` | Supplied categories, enclosure metadata and explicit caveats |

Atom alternate and enclosure links resolve `xml:base`. HTML/XHTML summaries remove executable markup; Atom text summaries remain literal text. Consumers must still render strings as text, not execute them as HTML. Missing titles remain null when a useful description or link exists. Empty items with no useful title, summary or link are skipped and counted. Full `content:encoded` articles and Atom content bodies are ignored.

`OUTPUT.feeds` has one outcome per normalized input feed. `COMPLETE` means that feed response was parsed and all matching items were selected. `EMPTY_FEED` means it contained no items. `EMPTY_IN_WINDOW` includes its excluded-date counters. `TRUNCATED` identifies selection or metadata limits. `FETCH_FAILED`, `PARSE_FAILED` and `UNSUPPORTED_FORMAT` distinguish failed sources. Feeds skipped after a total limit or deadline receive `NOT_FETCHED_LIMIT` or `NOT_FETCHED_DEADLINE`.

A run is `PARTIAL` when useful processing survives a failed or limited feed. If every source fails, it exits nonzero with `SOURCE_FAILED`. Invalid input and runtime storage failures also exit nonzero. A platform cap that stores fewer selected rows produces `DELIVERY_INCOMPLETE` and a nonzero exit. It is not reported as a complete export. Inspect `billing.deliveredItems`, per-feed delivery counts and the dataset together.

### Limits and fees

| Bound | Value |
| --- | --- |
| Input | 25 HTTPS URLs, port 443, 2,048 characters each, 64 KiB JSON |
| Per-feed and total item selection | 1 to 1,000; defaults 100 per feed and 5 total |
| Source response | 2 MiB encoded, 4 MiB decompressed, 64 HTTP headers |
| XML | 60,000 nodes, depth 32, 5,000 items per response; DTD/entities forbidden |
| Display metadata | 16,384 characters per title/summary, 50 tags, 20 enclosures; truncation flagged |
| Selected XML fields | 65,536 characters maximum; oversized fields fail that feed |
| Dataset selection bytes | 8 MiB across the run |
| Network | One feed at a time, 3 redirects, 15 seconds per feed, 120-second collection deadline |

No proxies, source cookies, source credentials, custom request headers or source retries are used. Public DNS answers are checked before aiohttp connects, and every redirect is validated. Private, loopback, local, multicast, transition and credential-bearing targets are rejected. Only the supplied feed is fetched. A source access failure is reported without bypassing it.

The configured price is $0.001 per item delivered to the default dataset, charged through Apify's automatic dataset-item event. The Actor adds no start fee or separate usage surcharge. Summary records and failed-source outcomes are not billable items. `maxChargeUsd` preselects at most `floor(maxChargeUsd / 0.001)` rows. A lower platform run cap can further reduce delivery. This field limits item charges; it does not guarantee a maximum total platform cost, including compute, transfer or storage.

A run writes the item batch once. The pinned dataset adapter disables internal SDK append retries while retaining SDK event limits and synthetic-event accounting. An uncertain append reports unknown delivery/charge counts. Restarting a completed run replays its receipt without a source fetch or append. Incomplete state fails closed. A fresh run is a new export and may charge for the same source items again.

### Scope and evidence

Private hosted tests have exercised the bounded feed and delivery workflows under Limited permissions. The item and receipt contracts are in `item_schema.json` and `output_record_schema.json`. This evidence does not establish cheaper total cost, greater accuracy or exclusive features compared with other RSS Actors. Usage-priced alternatives can be cheaper for some workloads.

Only submit public feeds you are permitted to retrieve. Feed availability does not itself grant rights to republish the publisher's content.

# Actor input Schema

## `feedUrls` (type: `array`):

One to 25 explicit public RSS 2.0 or Atom 1.0 HTTPS URLs on port 443. No credentials, source authentication or discovery. Duplicate normalized inputs are fetched once.

## `publishedFrom` (type: `string`):

RFC 3339 timestamp with Z or a numeric offset. Normalized to UTC. Applies to dateField, including updated when selected. Omit for no lower bound.

## `publishedBefore` (type: `string`):

RFC 3339 timestamp with Z or a numeric offset. Items at this instant are excluded. Must be later than the start. Omit for no upper bound.

## `dateField` (type: `string`):

Choose native item publication or update time. RSS 2.0 pubDate is published; RSS has no native updated date. Missing values remain null.

## `includeUndated` (type: `boolean`):

With a window, include undated items labeled UNKNOWN\_DATE. Without a window, undated items are included regardless of this option.

## `maxItemsPerFeed` (type: `integer`):

Delivered selection per feed after date filtering and deduplication. Feeds are processed in input order; item order follows each feed.

## `maxItems` (type: `integer`):

Run-wide item selection cap. Later feeds may be NOT\_FETCHED\_LIMIT.

## `maxChargeUsd` (type: `number`):

Preselect at most floor(this amount / 0.001) useful rows. The platform run limit may reduce delivery further. This is an item fee ceiling, not a compute or storage cost ceiling.

## Actor input object example

```json
{
  "feedUrls": [
    "https://www.rssboard.org/files/sample-rss-2.xml"
  ],
  "dateField": "published",
  "includeUndated": false,
  "maxItemsPerFeed": 100,
  "maxItems": 5,
  "maxChargeUsd": 0.005
}
```

# Actor output Schema

## `items` (type: `string`):

No description

## `outcomes` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("sapph1re/rss-atom-date-window-export").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("sapph1re/rss-atom-date-window-export").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call sapph1re/rss-atom-date-window-export --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,sapph1re/rss-atom-date-window-export"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/cC4bcAITn7kAAqgg3/builds/i4hvcu5am652XWo2M/openapi.json
