# Article Extractor: News & Blog Text to Markdown (`humble-echidna/article-extractor`) Actor

Extract news and blog articles from any URL, or find the newest via a site's RSS/Atom feed or sitemap. One clean row each: title, author, published and modified dates, lead image, language, main text as plain text and Markdown, word count, canonical URL. Only-new-articles mode for monitoring.

- **URL**: https://apify.com/humble-echidna/article-extractor.md
- **Developed by:** [Michael Costa](https://apify.com/humble-echidna) (community)
- **Categories:** News, AI, Developer tools
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 articles

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

### What does Article Extractor do?

**Article Extractor** takes **news and blog article URLs**, or **websites, RSS/Atom feeds or sitemaps** to find
articles on, and returns one clean row per article: **title, author, published date, lead image, language and the
main text** as plain text and Markdown. Navigation, cookie banners, share buttons and footers are removed.

[Input fields](https://apify.com/humble-echidna/article-extractor/input-schema) ·
[API](https://apify.com/humble-echidna/article-extractor/api) ·
[Use it from Claude, ChatGPT or Cursor (MCP)](#can-i-use-article-extractor-from-an-ai-agent-mcp)

**Jump to:** [Monitor sites](#monitor-sites-for-new-articles) ·
[Fields](#what-data-does-article-extractor-return) ·
[Price](#how-much-does-it-cost-to-extract-articles) ·
[How to use](#how-to-extract-articles-from-a-website) ·
[Input](#input) · [Output](#output) ·
[Chain after another actor](#chain-it-after-another-actor) ·
[AI agents (MCP)](#can-i-use-article-extractor-from-an-ai-agent-mcp) · [Limits](#limits) · [FAQ](#faq)

**Try it in one click:** the input comes pre-filled with the Rust blog and 3 articles. That's 3 articles: $0.003,
plus the $0.00005 start fee (3 × $0.001 per article). **Then replace it with the sites or articles you actually want.**

### Monitor sites for new articles

Article Extractor can check a list of blogs or news sites on a schedule and give you only the articles published
since its last run, with their full text. Set it up once:

1. **Save a task.** Fill in **Websites, feeds or sitemaps**, turn on **Only new articles since the last run**
   (`onlyNewArticles: true` in the API), then click **Save as a new task** at the top right of the actor's page. The
   first run returns the newest articles up to **Max articles per site**; later runs return only articles this search
   hasn't returned before.
2. **Schedule it.** In Apify Console, open **Schedules**, click **Create new**, pick the task and set how often it runs
   (for example every morning at 07:00, cron `0 7 * * *`).
3. **Send the new articles where you work,** from the task's **Integrations** tab:
   - **Slack:** a message in the channel you choose when a run succeeds (you pick the events and can edit the
     message).
   - **Email:** *Send results email via Gmail* sends the run's results, with the dataset attached.
   - **Webhook:** a POST to your URL on the `ACTOR.RUN.SUCCEEDED` event. The payload's `resource.defaultDatasetId`
     points to the new articles: `GET https://api.apify.com/v2/datasets/<defaultDatasetId>/items?format=json` with
     your API token.
   - **Make, Zapier or n8n:** each has an Apify step that starts on a finished run and reads its dataset.

A run that finds nothing new returns 0 articles and costs only the $0.00005 start fee. Slack and email are sent for
every successful run, including a quiet one; to hear only about new articles, use the webhook or Make/Zapier/n8n and
skip runs whose dataset is empty. Add the **run failed** event too, so a failed run doesn't go unnoticed. The first
few runs may also return older articles the first run didn't reach (see the FAQ). Keep **Find articles from** and
**Article URL patterns** fixed: changing them starts a new list.

### What data does Article Extractor return?

| Field | Example | Notes |
|---|---|---|
| `title` | `Announcing a Maintainer in Residence` | |
| `author` | `Jakub Beránek` | Names only, never profile links or email addresses; `null` when not stated. |
| `publishedAt`, `modifiedAt` | `2026-09-22T00:00:00Z` | ISO 8601 UTC. |
| `text` | `At the end of August, we announced...` | Main text as plain text. |
| `markdown` | `# Announcing a Maintainer in Residence...` | Main text as Markdown (headings, lists, tables, code, links). |
| `wordCount` | `740` | |
| `leadImageUrl` | `https://www.rust-lang.org/static/images/rust-social-wide.jpg` | |
| `language`, `siteName`, `description` | `en` | From the page's metadata; `null` when not stated. |
| `url`, `canonicalUrl` | `https://blog.rust-lang.org/2026/09/22/...` | |
| `discoveredVia`, `discoveredFrom` | `feed`, `https://blog.rust-lang.org/feed.xml` | How the article was found: `input`, `feed`, `sitemap` or `dataset` (with the dataset id). |
| `sourceTitle`, `sourceIndex` | `"Rust 1.83.0 released"`, `4` | From the dataset item the article came from (see [Chain it after another actor](#chain-it-after-another-actor)); `null` otherwise. |
| `id` | `dcb1e0eadb1f512f0c9b3410` | From the article URL, the same on every run. |

Every article has the same fields; the full record is under [Output](#output).

### How much does it cost to extract articles?

You pay per article returned: **$1.00 per 1,000 articles**, plus $0.00005 each time a run starts. Feeds and
sitemaps aren't charged, and neither are articles that fail, are skipped, or were returned already in this run.
Pages that need JavaScript, are blocked by `robots.txt`, opt out of AI use, or turn out not to be articles are not
charged either.

**It's cheaper on paid Apify plans:** $0.90 per 1,000 articles on Starter, $0.80 on Scale and $0.70 on Business. The prices on this page are the Free-plan price, so on a paid plan you pay less than the examples show.

- **The example below:** 3 articles × $0.001 = $0.003, plus the $0.00005 start fee.
- **A month, for example:** 20 sites checked daily with only-new on, about 5 new articles per site per day:
  20 × 5 × 30 = 3,000 articles × $0.001 = **$3.00**, plus 30 starts ($0.0015).
- **Caps:** **Max articles per run** in the input, and **Maximum cost per run** in the run options; it stops cleanly
  at whichever comes first. Each article is counted against the limit before it's fetched (and given back if it
  fails), so a capped run never fetches articles it can't return.

### How to extract articles from a website

1. Open the actor and paste sites (`https://blog.rust-lang.org/`), feed URLs or sitemap URLs into **Websites, feeds or
   sitemaps**, or single pages into **Article URLs**.
2. Set **Max articles per site** (newest first).
3. Click **Start**.
4. Open the **Output** tab and export the articles as JSON, CSV or Excel, or read them through the API.
5. To follow the sites, save it as a task and schedule it (see *Monitor sites for new articles* above).

For a site, it reads the site's own **feed** (found automatically from its home page) or, when there's none, its
**sitemap**, and extracts the **newest articles first**.

### Example: the Rust blog

The pre-filled input, with **Only new articles** turned on:

```json
{"sites": ["https://blog.rust-lang.org/"], "maxArticlesPerSite": 3, "onlyNewArticles": true, "discoverFrom": "auto"}
```

The newest of the 3 articles (real output from a local run on 2026-09-25; `text`, `markdown` and `url` shortened):

```json
{
  "id": "dcb1e0eadb1f512f0c9b3410",
  "url": "https://blog.rust-lang.org/2026/09/22/announcing-a-maintainer-in-residence-scott-schafer-...",
  "title": "Announcing a Maintainer in Residence: Scott Schafer for the Cargo team | Rust Blog",
  "author": "Jakub Beránek",
  "publishedAt": "2026-09-22T00:00:00Z",
  "leadImageUrl": "https://www.rust-lang.org/static/images/rust-social-wide.jpg",
  "language": "en",
  "text": "At the end of August, we announced our first Maintainers in Residence, Rust Project contributors who...",
  "wordCount": 740,
  "discoveredVia": "feed",
  "discoveredFrom": "https://blog.rust-lang.org/feed.xml"
}
```

The site's feed was found from its home page. A second run straight after returned the next 3 older articles, not the
same ones: the first run stops at 3 per site, and later runs work through the older ones before settling on newly
published posts (see the FAQ).

### Ready-to-run examples

Each example opens with the input already filled in. Run it as it is, or change the input first.

- **[Get a blog's latest articles as clean text and Markdown](https://apify.com/humble-echidna/article-extractor/examples/blog-latest-articles-text)**: Give it a blog or news site and get its newest articles with title, author, date and the full text as Markdown, without menus or ads.
- **[Monitor tech blogs for new articles](https://apify.com/humble-echidna/article-extractor/examples/monitor-new-blog-articles)**: Run daily and get only the articles published since the last run, from several blogs at once, with full text as Markdown.

### Input

| Field | What it does |
|---|---|
| **Websites, feeds or sitemaps** | One per line: a site (`https://blog.rust-lang.org/`), a feed URL, or a sitemap URL. |
| Article URLs | Individual article pages, extracted as given (no discovery, no "only new" memory). |
| Or: article URLs from a dataset (`datasetId`) | One of your Apify datasets, e.g. RSS & Atom Feed Reader's results: each item's link is extracted, and the two fields above are ignored. See [Chain it after another actor](#chain-it-after-another-actor). |
| Field with the article URL (`datasetUrlField`) | Only with a dataset. Empty (default): found automatically among `url`, `link` and `articleUrl`, then one level down (`article.link`). |
| Max articles per site | Newest first, at most this many per site (default 3, up to 500). |
| Only new articles since the last run | Skip articles this search already returned from that site. |
| Find articles from | Auto (feed, else sitemap), feed only, or sitemap only. |
| Article URL patterns | Only discovered URLs matching one of these (`/blog/`, `https://example.com/news/*`). |
| Max articles per run | Cap the total across all inputs. |

```json
{
  "sites": ["https://blog.rust-lang.org/", "https://www.djangoproject.com/weblog/"],
  "maxArticlesPerSite": 10,
  "onlyNewArticles": true
}
```

### Output

One row per article, always with these fields (`null` when neither the page nor its feed/sitemap says):

```json
{
  "id": "dcb1e0eadb1f512f0c9b3410",
  "url": "https://blog.rust-lang.org/2026/09/22/announcing-a-maintainer-in-residence/",
  "canonicalUrl": null,
  "title": "Announcing a Maintainer in Residence",
  "author": "Jakub Beránek",
  "publishedAt": "2026-09-22T00:00:00Z",
  "modifiedAt": "2026-09-22T00:00:00Z",
  "leadImageUrl": "https://www.rust-lang.org/static/images/rust-social-wide.jpg",
  "language": "en",
  "siteName": null,
  "description": "Empowering everyone to build reliable and efficient software.",
  "text": "At the end of August, we announced our first Maintainers in Residence ...",
  "markdown": "# Announcing a Maintainer in Residence\n\nAt the end of August, ...",
  "truncated": false,
  "wordCount": 740,
  "input": "https://blog.rust-lang.org/",
  "discoveredVia": "feed",
  "discoveredFrom": "https://blog.rust-lang.org/feed.xml",
  "sourceTitle": null,
  "sourceIndex": null,
  "scrapedAt": "2026-09-24T12:00:00Z"
}
```

- `id` comes from the article URL and is the same on every run: deduplicate on it, or use it as a vector-store key.
- Metadata is read from the page's schema.org JSON-LD, Open Graph and `article:*` tags, common publisher meta tags
  and microdata; the feed (or a Google News sitemap) fills in the title, author and date when the page doesn't say.
- `text` and `markdown` are capped at 500,000 characters each (`truncated`). Pages over 5 MB of HTML are skipped.

### Run it on a schedule, or from your own code

- **[Schedule](https://docs.apify.com/platform/schedules):** save the input as a
  [task](https://docs.apify.com/platform/actors/running/tasks) and add it to a schedule, as in *Monitor sites for new
  articles* above.
- **[API](https://apify.com/humble-echidna/article-extractor/api):** fetch a task's latest results with
  `GET https://api.apify.com/v2/actor-tasks/<task id>/runs/last/dataset/items?status=SUCCEEDED&format=csv` and your
  API token (`format` can also be `json` or `xlsx`).
- **Webhooks and automation:** a [webhook](https://docs.apify.com/platform/integrations/webhooks) when a run
  succeeds, or Make, Zapier or n8n through [Apify's integrations](https://docs.apify.com/platform/integrations).

#### Chain it after another actor

To get the full text of what another actor found, run Article Extractor right after it finishes with an integration
(any actor whose results have a link per article, e.g.
[RSS & Atom Feed Reader](https://apify.com/humble-echidna/rss-feed-reader),
[GDELT News Search](https://apify.com/humble-echidna/gdelt-news) or a news scraper):

1. Open the other actor or its saved task, go to the **Integrations** tab and add **Apify actor** →
   **Article Extractor**, triggered when a run **succeeds**.
2. Set `"datasetId": "{{resource.defaultDatasetId}}"` in the input (Apify fills in the finished run's dataset) and
   add **Max articles per run** if you want a cap.

Every successful feed or news run then produces a dataset of full articles, with no code. Each item's `url` is
extracted (or `link`, `articleUrl`, or the field you name in `datasetUrlField`), and **Websites, feeds or sitemaps**
and **Article URLs** are ignored, defaults included, so a chained run never fetches the Rust blog. Items without a
link are skipped, and an article listed twice is extracted and charged once. Each article carries `sourceTitle` and
`sourceIndex` (its row in the other dataset, 0 = the first) to join it back. From the API it's the same input: pass
the finished run's `defaultDatasetId` as `datasetId`. A run reads at most the first 20,000 items and 10,000 article
URLs of a dataset, with your own account's access, read-only; `RUN_STATS.dataset` says how many were read and
skipped.

To pay only for new articles, turn on the feed reader's own **Only new items** so each of its runs lists just what's
new; Article Extractor's **Only new articles** applies to sites, not to a dataset.

#### Can I use Article Extractor from an AI agent (MCP)?

Yes, through [Apify's MCP server](https://docs.apify.com/platform/integrations/mcp), from Claude, ChatGPT, Cursor or
any other MCP client. Add this to your client's MCP configuration (or let the agent find it with the server's actor
search); your client signs you in to Apify:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=humble-echidna/article-extractor"
    }
  }
}
```

To use an [Apify API token](https://console.apify.com/settings/integrations) instead of signing in, add
`"headers": {"Authorization": "Bearer <APIFY_TOKEN>"}` next to `url`.

The agent passes the same input JSON as above, usually with **Article URLs** for pages it already has. A field
left out takes its default, and **Websites, feeds or sitemaps** defaults to the Rust blog, so for article URLs only
pass `{"articleUrls": ["https://..."], "sites": []}`. An agent that has just run a feed reader or news scraper can pass
its dataset instead: `{"datasetId": "<dataset id>"}` (the other fields' URLs are then ignored). Keep **Max articles per site** low so answers stay small;
`markdown` is the field to hand to the model.

### Who it's for

Anyone who follows a set of blogs or news sites and needs the **full articles**, not just the headlines: media
monitoring, competitor and industry news tracking, newsletters and research digests, and AI pipelines that summarise
or index new posts. Give it the sites once, schedule it with **Only new articles**, and each run returns just what
was published since the last one, with author, date and clean text.

### Why this one?

- **One flat price, no usage bill.** You pay per result at the price above and nothing else: no compute, proxy or storage charges on top, apart from the $0.00005 run-start fee, so you know what a run costs before it starts. Results you don't get aren't charged.
- **Only new articles since the last run.** Each site's articles are remembered in your own Apify account (per
  site, per search), so a scheduled run never returns (or charges for) the same article twice.
- **Finds the articles for you.** Give it a blog or news site: it discovers its RSS, Atom or JSON feed, or falls back
  to its sitemap (including sitemap indexes and Google News sitemaps), and orders the articles newest first. URL
  patterns keep a sitemap to the article pages.
- **A stable schema.** Every row has the same fields, always in the same format: dates in ISO 8601 UTC, authors as
  names (never profile links or email addresses), absolute URLs. A field the page and its feed don't state is
  `null`, never guessed.
- **Clean text, twice.** Plain text for search and NLP, Markdown (headings, lists, tables, code, links) for LLMs
  and RAG.
- **Honest charging.** Pages that fail, need JavaScript, are blocked by `robots.txt`, opt out of AI use, or turn
  out not to be articles are **not charged**, and neither is an article listed twice.
- **Fast and cheap.** Plain HTTP, no browser: **$1.00 per 1,000 articles.**

### Limits

- **No JavaScript.** Pages whose text is built in the browser come back as "needs JavaScript" and aren't charged.
- **No logins or paywalls,** and no getting around bot protection.
- **No presets** for sites whose terms forbid crawling (Medium and Substack, for example).
- **robots.txt and politeness.** It checks each site's `robots.txt` before every request, including feeds, sitemaps
  and every redirect hop, and skips what it disallows (`blockedByRobots` in `RUN_STATS`, not charged). It identifies
  itself as `HumbleEchidnaApify/1.0 (+https://apify.com/humble-echidna)`; rules for `User-agent: HumbleEchidnaApify`
  apply to it. It honours `Crawl-delay` and `Retry-After`, and makes at most 2 requests at a time to one site.
- **It honours opt-outs from AI use.** Its output is pitched for LLMs, so a page that a site's `robots.txt`
  disallows for any of the well-known AI crawlers (Google-Extended, Applebot-Extended, CCBot, GPTBot, ChatGPT-User,
  OAI-SearchBot, ClaudeBot, Claude-User, Claude-SearchBot, anthropic-ai, Claude-Web, PerplexityBot,
  Perplexity-User) isn't fetched (`optedOutOfAI`, not charged). Blocking only one company's crawler (Bytespider,
  Meta-ExternalAgent, Amazonbot and the like) isn't an opt-out of AI use.
- **Sizes:** `text` and `markdown` are capped at 500,000 characters each; pages over 5 MB of HTML are skipped.

### FAQ

#### Why did a site return nothing, or the wrong pages?

Without a feed, the sitemap lists every page of a site, not just
articles: add **Article URL patterns** (e.g. `/news/`), or give the news sitemap's URL directly. Pages under 50
words (tag pages, listings) are skipped. Sitemap entries are taken newest first by the date the sitemap gives
(a news publication date or `lastmod`), else by a date in the URL (`/2026/09/22/`), else in the order listed. `RUN_STATS` says, per input, where the articles came from and why any
were skipped.

#### How does "only new" decide what's new?

An article is new when this search hasn't returned its URL from that
site before, under the link the feed or sitemap lists or the address that link redirects to (`http` to `https`,
a trailing slash): a redirected article is never returned or charged twice. The first run returns the newest ones
up to your per-site limit; older articles it didn't reach are returned by later runs once nothing newer is waiting.
Changing the discovery mode or URL patterns starts a new list.

#### Why did an article come back as "needs JavaScript"?

Its text is built in the browser, and this actor doesn't run one.
It's not charged.

#### Why does it refuse `localhost`, a private address or a URL with a port?

It only fetches public web pages on the
standard ports (80 and 443), and checks every address (and redirect) first.

#### How is this different from other article extractors?

The most-used article extractor in the Store is free and more configurable (its own crawler, many options). Pick
this one if you want scheduled "only new" monitoring of sites by their feeds or sitemaps with one predictable
output format, at a low per-article price.

#### Is it legal to extract articles with it?

It fetches only the pages, feeds and sitemaps of the sites you name, as a normal logged-out
visitor, and follows each site's `robots.txt`, including its opt-outs for AI crawlers. Feeds and sitemaps are
published by site owners for machines to read. It doesn't log in or get around any protection. What you do with
the content (copyright, the site's terms) is your responsibility, as with any page you save.

### Related actors

| Actor | Use it when |
|---|---|
| [RSS & Atom Feed Reader](https://apify.com/humble-echidna/rss-feed-reader) | The feed already carries what you need (title, link, date, often the full text): it's cheaper and doesn't open the article pages. Use Article Extractor when feeds only give a summary (chain it after the feed reader to get the full text of each item), or a site has no feed. |
| [Website & Page to Markdown for RAG and LLMs](https://apify.com/humble-echidna/page-to-markdown) | You want documentation and other non-article pages, whole sites, or heading-based chunks for RAG. Article Extractor is for dated articles with an author. |

### Feedback and support

Found a bug, or need a field that isn't here? Open an issue on the **Issues** tab with the input you used.

### Versions

Current version: **1.1**. See the Changelog tab for what changed in each version.

# Changelog

This Actor's version history is a separate document: https://apify.com/humble-echidna/article-extractor/changelog.md

# Actor input Schema

## `sites` (type: `array`):

Sites to find articles on, one per line: a website or blog (https://blog.rust-lang.org/; its RSS/Atom feed is found from the page), a feed URL (https://blog.rust-lang.org/feed.xml), or a sitemap URL (https://example.com/news-sitemap.xml). The newest articles are extracted, up to maxArticlesPerSite. Only public http/https addresses on ports 80 and 443. Left out, it defaults to the Rust blog: pass an empty list to extract only articleUrls. Ignored when datasetId is set.

## `articleUrls` (type: `array`):

Individual article pages to extract, one per line, e.g. https://blog.rust-lang.org/2024/11/28/Rust-1.83.0.html. Each is extracted as given (no discovery, no 'only new' memory). Combines with sites, which defaults to the Rust blog: set sites to an empty list to get only these pages. Ignored when datasetId is set.

## `datasetId` (type: `string`):

One of your Apify datasets, picked or given by id, e.g. RSS & Atom Feed Reader's results or the run this one is chained after: each item's article link is extracted like articleUrls; sites and articleUrls (with their defaults) are ignored and onlyNewArticles doesn't apply. Items with no web address in the link are skipped; duplicates are extracted once. Each result carries sourceTitle and sourceIndex from its item. At most the first 20,000 items and 10,000 article URLs are read, read-only.

## `datasetUrlField` (type: `string`):

Only with datasetId: the item field that holds the article URL, e.g. `url`, or a dotted path such as `article.link`. Leave empty (the default) to find it automatically: the first of url, link and articleUrl that has a web address in the first 100 items, then the same names one level down (article.url).

## `maxArticlesPerSite` (type: `integer`):

For each entry in sites: extract at most this many articles, newest first. 1 to 500, default 3.

## `onlyNewArticles` (type: `boolean`):

Default false. When true, for each site, skip the articles this search already returned in an earlier run (remembered in your Apify account, per site, discovery mode and URL patterns). The first run returns the newest ones. Good for scheduled monitoring.

## `discoverFrom` (type: `string`):

Where a site's list of articles comes from. `auto` (the default): its feed, else its sitemap. `feed`: feed only (RSS, Atom, JSON Feed). `sitemap`: sitemap only. A sitemap URL in sites is always read as a sitemap.

## `urlPatterns` (type: `array`):

Only extract discovered articles whose URL matches at least one of these, one per line, e.g. /blog/ or https://example.com/news/\*. `*` matches anything (the pattern must then match the whole URL); without `*` a pattern matches anywhere in the URL. Case-insensitive. Most useful with sitemaps, which list every page of a site. Leave empty (the default) for all.

## `maxResults` (type: `integer`):

Stop after this many articles in total across all inputs, e.g. 20. Minimum 1; leave empty (the default) for no limit. The run also stops cleanly at the maximum cost per run you set in the run options, whichever comes first. Set it to keep a run small and quick.

## Actor input object example

```json
{
  "sites": [
    "https://blog.rust-lang.org/"
  ],
  "maxArticlesPerSite": 3,
  "onlyNewArticles": false,
  "discoverFrom": "auto"
}
```

# Actor output Schema

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

No description

## `runStats` (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 = {
    "sites": [
        "https://blog.rust-lang.org/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("humble-echidna/article-extractor").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 = { "sites": ["https://blog.rust-lang.org/"] }

# Run the Actor and wait for it to finish
run = client.actor("humble-echidna/article-extractor").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 '{
  "sites": [
    "https://blog.rust-lang.org/"
  ]
}' |
apify call humble-echidna/article-extractor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,humble-echidna/article-extractor"
        }
    }
}
```

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/vwlYgZtbME5PF4WTi/builds/nQJT1ELzCDGLoAeFB/openapi.json
