# RSS News Headlines (`openrows/rss-news-headlines`) Actor

Headlines, links and publish dates from a list of RSS/Atom/RDF feeds you supply. No article bodies fetched.

- **URL**: https://apify.com/openrows/rss-news-headlines.md
- **Developed by:** [openrows](https://apify.com/openrows) (community)
- **Categories:** News
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$2.00 / 1,000 feed entries

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## RSS News Headlines

Headlines, links and publish dates from the RSS 2.0, Atom or RDF (RSS 1.0) feeds you point it at.
No article bodies fetched, ever — feeds already carry a headline, a link, a date and (often) a short
summary, and that is all this Actor takes from them. HTTP-only, no browser, so runs are fast and cheap.

The incumbents compared during scoping fetch the full article body behind each link by default
(heavier to run, and priced accordingly). This one deliberately does not: if you only need headlines
for monitoring, alerts or a lightweight aggregation, you are not paying for bodies you throw away.

### What data you get

For every feed entry the Actor returns:

| Field         | Description                                                                                                                                                 |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `url`         | The feed URL this entry was extracted from (same as `feedUrl`)                                                                                              |
| `scrapedAt`   | ISO 8601 timestamp of the extraction                                                                                                                        |
| `feedTitle`   | The feed's own title                                                                                                                                        |
| `feedUrl`     | The feed URL from your input that this entry came from                                                                                                      |
| `title`       | The entry's headline                                                                                                                                        |
| `link`        | URL of the article the headline points to — never fetched by this Actor                                                                                     |
| `publishedAt` | ISO 8601 publish date, parsed from the feed. `null` when the feed gives none                                                                                |
| `summary`     | Up to 300 characters total (incl. a trailing "…" when cut), HTML stripped, e-mails redacted. `null` when the feed gives no summary — never the article body |
| `categories`  | Category/tag labels the feed attaches to the entry, if any                                                                                                  |
| `guid`        | The feed's own unique ID for the entry (RSS `guid` / Atom `id`), used to de-duplicate                                                                       |

### Input

| Option               | Type    | Default | Description                                                                             |
| -------------------- | ------- | ------- | --------------------------------------------------------------------------------------- |
| `feedUrls`           | array   | -       | RSS/Atom/RDF feed URLs to read. Give at least one.                                      |
| `keywords`           | array   | `[]`    | Keep only entries whose title or summary contains one of these words (case-insensitive) |
| `since`              | string  | -       | Keep only entries published on or after this ISO 8601 date/time                         |
| `maxItems`           | integer | `100`   | Stop after this many entries (max 10,000). Also your cost cap.                          |
| `proxyConfiguration` | object  | off     | Proxy settings. Feeds are rarely blocked, so this is off by default.                    |

Example input:

```json
{
    "feedUrls": [{ "url": "https://hnrss.org/newest" }, { "url": "https://blog.rust-lang.org/feed.xml" }],
    "keywords": ["security", "release"],
    "maxItems": 50
}
```

### Output example

```json
{
    "url": "https://blog.rust-lang.org/feed.xml",
    "scrapedAt": "2026-09-22T10:15:30.000Z",
    "feedTitle": "Rust Blog",
    "feedUrl": "https://blog.rust-lang.org/feed.xml",
    "title": "Announcing Rust 1.98.0",
    "link": "https://blog.rust-lang.org/2026/08/20/Rust-1.98.0/",
    "publishedAt": "2026-08-20T00:00:00.000Z",
    "summary": "Today the Rust team is happy to announce a new version of Rust, 1.98.0…",
    "categories": [],
    "guid": "https://blog.rust-lang.org/2026/08/20/Rust-1.98.0/"
}
```

A run summary (items pushed, items skipped by category, feeds fetched, failed requests by category,
robots.txt outcomes per host, stop reason) is stored in the run's key-value store under the key
`OUTPUT`.

### Pricing

**Pay per result.** You are charged per result and nothing else: no platform usage, no compute units.
Feed requests, retries and failed requests are free. The current rate is on the *Pricing* tab of this
Actor — that is the only place it is set, so no figure is repeated here.

- `maxItems` caps the number of results, and therefore the cost, of a run.
- The run also stops when it reaches the *maximum total charge* you set for the run in Apify Console
  or through the API.

### Tips

- Start with `maxItems: 20` to check the fields before a large run.
- `keywords` and `since` are applied after parsing, so they never cost you an extra request — they
  only reduce how many of a feed's own entries are kept.
- A feed with more entries than fit under `maxItems` still counts as one request; you are not charged
  per feed, only per entry kept.

### Limitations

- No article bodies, ever — including as a fallback. Some Atom feeds give an entry a `<content>`
  (the full body) but no `<summary>`; for those entries `summary` is `null`, not the body. If you need
  the full text of the linked pages, this is not that Actor — by design (see the pricing note above).
- A feed behind a login, or one your `feedUrls` points at with the wrong URL, is not fetched.
- Some feeds omit a publish date or a summary entirely; the corresponding output fields are `null`
  rather than guessed.
- `since` only filters entries whose date the feed gives *and* this Actor could parse; an entry with
  no parseable date is kept rather than silently dropped. `since` itself must be a real calendar date
  in `YYYY-MM-DD` form, optionally with a time part that ends in `Z` (never a numeric offset or a bare
  local time, which would leave "before `since`" depending on whose timezone is asking) — anything
  else fails the run instead of silently filtering out everything.

**Source caveats.** This Actor reads whatever the feed itself publishes. It does not check the feed
publisher's own terms for you — see "Data and compliance" below.

### Data and compliance

This Actor is site-agnostic: **you choose the feed URLs, and you are responsible for the sources you
point it at.** With that boundary:

- It fetches only the feed URLs you give it — never a linked article page, and never anything a feed
  did not itself list.
- It fetches and respects `robots.txt` for every host a feed URL belongs to, before requesting the
  feed itself — see "How robots.txt is handled" below.
- It identifies itself with a plain `openrows/rss-news-headlines` User-Agent and sends no headers that
  imitate a browser.
- It does not collect names, e-mail addresses or phone numbers. Specifically, it never reads a feed's
  `author`, `dc:creator`, `byline` or `contributor` fields in the first place — a public byline is not
  extracted even when a feed carries one — and any e-mail address that turns up inside the free-text
  `title`, `summary` or `categories` fields is redacted before the item is stored, including one
  written as an HTML/numeric entity to dodge a plain-text match. These fields are otherwise the feed's
  own words, passed through as published. This redaction covers those three text fields only: a
  `mailto:` address used as an entry's `guid` or `link` (rare, but seen on some feeds) is not scanned
  for and passes through unredacted.
- It sends few requests in parallel, waits between requests to the same host, and stops instead of
  working around a block (a 401/403/429 response is recorded and not retried under a different
  identity).

#### How robots.txt is handled

Before the first feed on a host is fetched, the Actor fetches that host's `robots.txt` once and obeys
it for the rest of the run. Rules are read for the product token `openrows`, falling back to the `*`
group when the file does not name us, with `*` and `$` wildcards and the standard "longest matching
rule wins" precedence. A `Crawl-delay` set for us is honoured, up to 10 seconds. When a feed URL
redirects, the URL the redirect actually leads to is checked again against its own host's rules before
anything is read from it, so a redirect cannot carry the Actor onto a site, or a path, that its owner
puts off limits.

- **Disallowed feed URLs are never requested.** They are reported under `skipped.robotsDisallowed` in
  the run summary, so you can see exactly how many of your input feeds the site puts off limits.
- **No `robots.txt` (404 or 410) means no rules**, and the host is crawled normally. It is counted as
  `robotsAbsent` in the summary.
- **A `robots.txt` we cannot read means the host is skipped, not crawled.** Any other response — 401,
  403, 429, a 5xx, a timeout, a network failure, or a 200 that turns out to be an error or login page —
  leaves us without the site's rules, and this Actor will not guess. Every feed on that host is
  skipped and counted under `skipped.robotsUnknown`, and the host and the status that stopped us are
  listed under `robots.unknownHosts` in the summary. If a feed you supplied returns no results, look
  there first.

**Removal requests.** If you believe this Actor exposes data it should not, open an issue on the
Actor's *Issues* tab and state the feed URL(s) concerned. Requests are answered there, and the fields
or feeds in question are removed.

You are responsible for using the extracted data in line with the terms of the feeds you point this
Actor at, and the laws that apply to you.

### Support

Report bugs and request fields on the *Issues* tab of this Actor. Include the run ID.

# Actor input Schema

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

RSS 2.0, Atom or RDF (RSS 1.0) feed URLs to read. One request per feed; article pages linked from a feed are never fetched. Give at least one.

## `keywords` (type: `array`):

Keep only entries whose title or summary contains at least one of these words or phrases (case-insensitive, matched as a substring). Leave empty to keep every entry.

## `since` (type: `string`):

Keep only entries published on or after this date/time (ISO 8601, e.g. "2026-09-01" or "2026-09-01T00:00:00Z" — zero-padded, and any time part must end in "Z", never a numeric offset or a bare local time). Entries whose feed gives no parseable publish date are kept regardless. The run fails if this is not that exact shape or not a real calendar date, rather than silently filtering out everything.

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

Stop after this many entries. You are charged per result, so this is also your cost cap. Maximum 10,000 per run; split a bigger job across runs.

## `proxyConfiguration` (type: `object`):

Proxy settings. Feeds are usually served without blocking, so this can normally be left off.

## `maxRequestsPerCrawl` (type: `integer`):

Hard cap on feed requests actually fetched. A feed a robots.txt check disallows is never queued and does not count against this cap. Defaults to 5 x Max results.

## Actor input object example

```json
{
  "feedUrls": [
    {
      "url": "https://hnrss.org/newest"
    }
  ],
  "keywords": [],
  "maxItems": 100,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (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 = {
    "feedUrls": [
        {
            "url": "https://hnrss.org/newest"
        }
    ],
    "keywords": [],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("openrows/rss-news-headlines").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 = {
    "feedUrls": [{ "url": "https://hnrss.org/newest" }],
    "keywords": [],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("openrows/rss-news-headlines").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 '{
  "feedUrls": [
    {
      "url": "https://hnrss.org/newest"
    }
  ],
  "keywords": [],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call openrows/rss-news-headlines --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,openrows/rss-news-headlines"
        }
    }
}
```

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/CkYZRC4peTaPRM4Ug/builds/SoJ8ybSPXiBpKkHbs/openapi.json
