# Medium Articles Scraper: Tags, Authors, Search, Full Text (`quarra/medium-articles-scraper`) Actor

Medium articles scraper for tags, authors, publications, keyword searches or article links: title, full text in Markdown, claps, responses, reading time, author with followers, publication, tags, paywall flag. Hundreds of articles per source, not just the latest 10.

- **URL**: https://apify.com/quarra/medium-articles-scraper.md
- **Developed by:** [Quarra Labs](https://apify.com/quarra) (community)
- **Categories:** News, Social media, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.80 / 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

## Medium Articles Scraper: Tags, Authors, Search, Full Text

Get Medium articles in bulk, without an account or API key. Give it tags, authors, publications, search keywords or
article links. Each article comes back with its full text as Markdown, claps, number of responses, reading time, word
count, tags, the author (bio and followers) and the publication. Hundreds or thousands of articles per tag, author or
publication, not just the latest 10 of an RSS feed. Member-only stories are marked and delivered as the preview any
visitor sees. Export as JSON, CSV or Excel, or read it through the Apify API.

**$4 per 1,000 articles**, plus a small start fee per run. Articles that no longer exist, articles your filters leave
out, repeats and inputs that fail are not charged.

### Quick start

1. Add a **tag** (`machine-learning`), an **author** (`@ev`), a **publication** (`towards-data-science`) or **search
   keywords**, or paste any Medium link into **Medium links or article IDs**.
2. Set **Max articles** and, if you want more than 100 from one source, **Max articles per source**.
3. Click **Start** and read the articles in the run's **Output** tab.

Like any Apify Actor, it can also be run and read through the Apify API, scheduled, and connected to webhooks, Make,
Zapier, n8n or Apify's MCP server for AI agents.

### What it is used for

- **Content research**: what is written about a topic, what got claps, which angles and titles work.
- **Competitor and creator tracking**: everything an author or a publication posts, with claps and responses.
- **Datasets for AI**: full articles as clean Markdown, with language, tags and dates, ready for retrieval or training
  pipelines (check the licence terms that apply to your use).
- **Trend monitoring**: the newest articles of a tag, on a schedule, or the most-read articles of each month.

### What you get

| | |
|---|---|
| Article ID, URL, title, subtitle | yes |
| Full text as Markdown (headings, links, code, lists, quotes, images) | yes, optional |
| Claps, people who clapped, responses | yes |
| Reading time, word count, language | yes |
| Tags | yes |
| Publication date and last update | yes |
| Author: name, username, bio, followers, picture | yes |
| Publication: name, address, followers | when the article is in one |
| Preview image | yes |
| Member-only flag, and whether the text is a preview | yes |
| Position in the source's results | yes |

Measured on 1,000 articles from 9 sources (17/10/2026): title, date, claps, reading time, language and text on 100 %,
subtitle on 97 %, author bio on 91 %, preview image on 88 %, tags on 90 %. A publication is set when the article was
published in one (52 % of the sample).

### Inputs

- **Medium links or article IDs**: any Medium link is read for what it is: an article (`medium.com/@ev/title-4916e42af749`,
  `medium.com/p/4916e42af749`, a publication's own domain), a tag page, an author profile, a publication or a search page.
  A link to a page of a source (`/@ev/latest`, `/@ev/about`, a publication's `/archive` or `/latest`, a `medium.com/feed/…` link) is read as that author, publication or tag. A bare 12-character article ID works too. Up to 50,000 per run.
- **Tags**: `machine-learning`, `Machine Learning` or `https://medium.com/tag/machine-learning`. Names are read as
  Medium spells its tags: `C++` is `cpp`, `C#` is `csharp`, `Node.js` is `nodejs` (the run summary says so). Accents are
  kept (`développement web`, `café`); if Medium has no such tag, the spelling without accents is tried and the run summary says so.
- **Authors**: `@ev`, `ev`, `https://medium.com/@ev` or `https://ev.medium.com`.
- **Publications**: `towards-data-science`, `https://medium.com/better-programming`, or a publication's own domain
  such as `blog.stackademic.com`.
- **Search keywords**: as typed in Medium's search box, or a `medium.com/search?q=…` link.
- Up to 2,000 tags, authors, publications and searches per run.
- **Max articles**: total articles the run delivers, counted exactly. **Max articles per source**: each tag, author,
  publication or search stops there.
- **Tag order**: newest first, or most read (the most-read articles of each month, newest month first, about 20 a month,
  back to the tag's oldest article).
- **Filters**: published after / before (a date such as `2026-01-31`), minimum claps, access (all, free only,
  member-only stories only). They apply to every article, article links included: an article they leave out is never
  charged, and a link they leave out gets a free `excluded` record that says which filter. An article whose date,
  claps or access Medium does not give is left out by a filter on that value.
- **Full text (Markdown)**: on by default. Turn it off for metadata only, which is lighter and faster.

Example, through the API:

```json
{
  "tags": ["machine-learning"],
  "authors": ["@ev"],
  "searchQueries": ["rag llm"],
  "maxItems": 1000,
  "maxResultsPerSource": 500,
  "publishedAfter": "2026-01-01",
  "minClaps": 50
}
```

### Output

One record per article in the dataset. A shortened article:

```json
{
  "type": "article",
  "status": "ok",
  "articleId": "99c9ffac0b02",
  "url": "https://medium.com/@isiomaasielue4/i-cried-over-an-env-file-my-week-6-at-dataraflow-99c9ffac0b02",
  "title": "I Cried Over an.env File: My Week 6 at Dataraflow",
  "subtitle": "I almost didn’t write this one properly. It is easier to say “this week I learnt SQL and pandas”…",
  "publishedAt": "2026-10-17T07:44:45.338Z",
  "authorName": "issy ~",
  "authorUsername": "isiomaasielue4",
  "authorUrl": "https://medium.com/@isiomaasielue4",
  "authorFollowers": 4,
  "publicationName": null,
  "publicationStatus": null,
  "tags": ["Data Science", "Python", "Sql", "Pandas", "Dataraflow Intern"],
  "claps": 0,
  "voters": 0,
  "responses": 0,
  "readingTimeMinutes": 4.4,
  "wordCount": 1071,
  "language": "en",
  "imageUrl": "https://miro.medium.com/v2/resize:fit:1400/1*G1NJm7RqLXFSEF1R7N3Gvw.png",
  "isMemberOnly": false,
  "isPreviewOnly": false,
  "content": "I almost didn’t write this one properly. …\n\n### **The setup that broke me**\n\n…",
  "input": "python",
  "inputType": "tag",
  "position": 1,
  "scrapedAt": "2026-10-17T07:55:16.025Z"
}
```

Fields that need a word of explanation:

- `status`: `ok` (delivered, charged), `unavailable` (free: an article ID that Medium no longer shows), `excluded`
  (free: an article link your filters leave out; `error` says which filter), `error` (free; `error` says why,
  `retryable` says if a later run may work).
- `isMemberOnly`: the story is behind Medium's paywall. Medium shows visitors without an account only the start of it:
  that is what you get, with `isPreviewOnly: true`. Nothing is unlocked, and no account is used. Articles that are free
  come whole (`isPreviewOnly: false`).
- `claps`: Medium's count (`null` if Medium does not give it, never a made-up 0). `voters` is how many people clapped;
  `responses` the comments under the article.
- `content`: the text as Markdown, faithful to what Medium shows (characters that Markdown would read as formatting are
  escaped). Images are links to Medium's image servers; videos and other embeds are links.
- `publicationStatus`: `published` (the article is in the publication given), `pending` (submitted to a publication
  that has not accepted it yet: `pendingPublicationName` names it, and the publication fields fill in once it does),
  or `null`.
- `position`: place in the source's results, from 1.

The run summary (counts per input, why the run stopped, notes) is the `OUTPUT` record of the run's key-value store.

### Pricing

Pay per event:

| Event | Price |
|---|---|
| Article | $4 per 1,000 |
| Run start | $0.005 per run |

Higher Apify plans pay less per article. Never charged: articles that no longer exist, articles your filters leave out,
error records, repeats (an article found by two sources is delivered once). Set **Maximum cost per run** in the run options and the run stops
before going over it.

Speed, measured on Apify (17/10/2026): 1,000 articles with full text in 63 s from 9 sources; 5,000 articles from 5 tags in 9 minutes, using 66 MB of memory. Without the full text it is lighter still.

### Limits

- **Search shows about 990 results per keyword search.** Medium returns no more for one search; the run summary says
  when a search reached this. Use more specific keywords, or tags and publications, which go much deeper.
- **Most read** is Medium's own ranking: about 20 articles per month for a tag, no more. Use **Newest first** with a
  date range to get everything.
- **A high minimum of claps on a tag sorted by date** is slow: the filter is applied after an article is read, so a run
  can read 13,000 articles to keep 17. Use **Most read** (the top articles of each month) or a
  **published after** date to narrow the reading.
- **Member-only stories** come as the preview Medium shows visitors without an account. Nothing behind the paywall is
  delivered.
- **Comments** are counted (`responses`) but their text is not scraped by this Actor.
- **Authors and publications** are listed newest first, except the stories pinned at the top of the profile or home
  page, which Medium lists first (as on the site).
- Medium decides what a tag, author or publication lists. A tag shows the articles that were tagged with it, not
  every article that mentions the word.

### FAQ

**Do I need a Medium account?** No.

**What if the run is restarted by the platform (migration or reboot)?** It resumes where it was: articles already in
the dataset are not delivered or charged again.

**Can I get articles behind the paywall?** No. You get what a visitor without an account sees, marked as a preview.

**Is it legal?** It collects public data shown to any visitor of Medium. Check the rules that apply to your use of the
data; the articles belong to their authors.

**Does the Actor send anything to Quarra?** Only when a run fails or runs out of time: the Actor, its build, the error type, the line of our code where it happened, and the memory and time the run was given, so we can fix it fast. Never your input, your results, your account or the run ID.

### Related tools from Quarra

- [Reddit Scraper](https://apify.com/quarra/reddit-scraper): posts and comments from subreddits, searches and users.
- [Google Trends Scraper](https://apify.com/quarra/google-trends-scraper): how interest in a topic moves over time.

# Actor input Schema

## `startUrls` (type: `array`):

Any Medium link, read for what it is: an article, a tag page, an author profile, a publication (also on its own domain, such as blog.stackademic.com) or a search page. A bare article ID (12 characters) also works. The filters below apply to these articles too.

## `searchQueries` (type: `array`):

Search Medium for these words, as the search box does. Medium shows about 990 results per search; use more specific words to go further.

## `tags` (type: `array`):

Tag names or links, such as machine-learning or https://medium.com/tag/python. Names are read as Medium spells its tags: C++ is cpp, C# is csharp, Node.js is nodejs. The tag's articles, newest first (see Tag order).

## `authors` (type: `array`):

Usernames or profile links, such as @ev or https://medium.com/@ev. All the author's stories, newest first (a story pinned at the top of the profile comes first, as on Medium).

## `publications` (type: `array`):

Publication names or links, such as towards-data-science, https://medium.com/better-programming or a publication's own domain (blog.stackademic.com). Its articles, newest first (stories pinned at the top of its home page come first, as on Medium).

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

Total number of articles delivered by the run, counted exactly. Free records (errors, articles that no longer exist) are not counted.

## `maxResultsPerSource` (type: `integer`):

Each tag, author, publication or search stops at this many articles.

## `includeContent` (type: `boolean`):

Add the article text as Markdown (headings, links, code, lists, images). For member-only stories Medium shows visitors without an account a preview only, and so does this Actor: those rows are marked isMemberOnly and isPreviewOnly. Untick for metadata only (lighter and faster).

## `tagSort` (type: `string`):

Newest first reads a tag from today backwards. Most read gives the most-read articles of each month, newest month first (Medium shows about 20 per month), until the limits, the dates below or the tag's oldest article.

## `publishedAfter` (type: `string`):

Only articles published on or after this date, such as 2026-01-31. Like every filter here, it applies to all articles, including those given by link: an article left out is never charged, and a link left out gets a free 'excluded' record saying why. Sources sorted by date stop early once they reach older articles.

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

Only articles published on or before this date (the whole day counts), such as 2026-03-01. A tag then starts from that month instead of today and reads back to its oldest article.

## `minClaps` (type: `integer`):

Only articles with at least this many claps (an article whose claps Medium does not give is left out). Applies to article links too.

## `access` (type: `string`):

Member-only stories are delivered as the preview Medium shows visitors without an account. Applies to article links too.

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

Connection. Keep the default (automatic). Costs are included in the price.

## Actor input object example

```json
{
  "startUrls": [
    "https://medium.com/tag/artificial-intelligence"
  ],
  "maxItems": 50,
  "maxResultsPerSource": 100,
  "includeContent": true,
  "tagSort": "newest",
  "minClaps": 0,
  "access": "all",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Every article with all its fields, and free records with the reason.

## `overview` (type: `string`):

One line per article: claps, responses, reading time, author, publication.

## `summary` (type: `string`):

Counts per input, why the run stopped, errors.

# 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 = {
    "startUrls": [
        "https://medium.com/tag/artificial-intelligence"
    ],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("quarra/medium-articles-scraper").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 = {
    "startUrls": ["https://medium.com/tag/artificial-intelligence"],
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("quarra/medium-articles-scraper").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 '{
  "startUrls": [
    "https://medium.com/tag/artificial-intelligence"
  ],
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call quarra/medium-articles-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,quarra/medium-articles-scraper"
        }
    }
}
```

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/7RGQEo3TZAtzzokBg/builds/mipwcPSmxu0EWDCuM/openapi.json
