# Medium Scraper: Articles by Tag, Author & Search (`precious_bathmat/medium-scraper`) Actor

Scrape Medium stories by tag, search, author or publication: title, author, followers, claps, responses, reading time, tags, member-only flag and publish date, plus the full text as Markdown. Top posts, authors and tags per source. No login.

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

## Pricing

from $1.00 / 1,000 stories

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

## Medium Scraper: Articles by Tag, Author & Search

Scrape **Medium stories** by **tag**, **search**, **author** or **publication**. For every story you get the **title, subtitle, author and their follower count, publication, publish date, claps, responses, reading time, word count, tags and member-only flag**, and optionally the **full text as Markdown and plain text**.

- **Four ways in**: tags (`artificial-intelligence`, `python`), Medium search, authors (`@username`) and publications (`medium.com/better-programming`), plus single story addresses
- **Six tag views**: newest, trending, top this week, month, year or of all time
- **Past Medium's 100-story limit per tag**: when you ask for more, the scraper also reads the tag's other views and Medium search for it, without duplicates
- **Full text** on request, with headings, lists, code blocks, links and images kept as Markdown
- **Top posts, top authors and related tags** for every tag, search, author and publication
- **No login, no API key, no browser**

### What does this Medium scraper do?

```
@zulie (author, 300 stories, 2020-2026)
 Median claps 2,483 · top story "If You Want to Be a Creator, Delete All..." 69,400 claps
tag python (top this year, at least 10 claps)
 403 stories in 76 seconds
search "rag pipeline"
 300 stories · top "Building a RAG Pipeline for 10M+ Documents" 1,977 claps
```

1. Add **tags, searches, authors, publications or story addresses**.
2. The scraper reads Medium's own story lists, the same ones its website shows, page by page.
3. You get **one row per story**, a **summary per source** and a CSV.

```mermaid
flowchart LR
    A[Tags · searches ·<br/>authors · publications] --> B[Medium story lists]
    B --> C[Claps, responses,<br/>reading time, tags]
    C --> D[Full text as<br/>Markdown, optional]
    C --> E[One row per story<br/>+ top posts per source]
```

### Who is it for?

- **Content marketers and writers** finding what gets claps in a topic before writing about it
- **Publications and editors** scouting authors by followers and claps
- **SEO and trend researchers** tracking what a topic publishes every day
- **AI and data teams** collecting technical articles as Markdown for RAG and training sets
- **Agencies** reporting on a brand's or a competitor's Medium publication

### What data do you get?

**Stories** (dataset, one row per story)

| Field | What it tells you |
|---|---|
| `title`, `subtitle`, `url`, `image` | The story |
| `authorName`, `authorUsername`, `authorFollowers`, `authorUrl` | Who wrote it and how big their audience is |
| `publication`, `publicationSlug`, `publicationFollowers`, `publicationUrl` | Where it was published, when it was |
| `publishedAt`, `updatedAt`, `daysSincePublished` | When |
| `claps`, `responses` | How readers reacted |
| `readingTimeMinutes`, `wordCount`, `language` | Length and language |
| `tags`, `isMemberOnly` | Medium's tags; whether it is behind the membership paywall |
| `markdown`, `text`, `fullTextIsPreview` | Full text, when **Full text** is on |
| `sourceType`, `source` | Which tag, search, author or publication found it |

`SUMMARIES` holds one summary per source: median claps, responses and reading time, member-only share, newest and oldest story, **top 10 stories**, **top 10 authors** by claps and **20 related tags**. `STORIES_CSV` has every story as flat columns.

### Example: 8 October 2026

**1,105 stories with full text in 2 minutes 58 seconds** from two tags, one search, two authors, one publication and one story address.

| Source | Stories | Median claps | Top story |
|---|---|---|---|
| tag `artificial-intelligence`, newest | 100 | 0 | 173 claps, all published that day |
| tag `python`, newest | 97 | 0 | 500 claps |
| search "rag pipeline" | 300 | 1 | "Building a RAG Pipeline for 10M+ Documents", 1,977 |
| author `@zulie` | 300 | 2,483 | "If You Want to Be a Creator, Delete All...", 69,400 |
| author `karpathy` | 8 (the whole profile) | 1,801 | "Software 2.0", 61,029 |
| publication `better-programming` | 300 | 193 | 2,977 |

- Newest stories in a big tag are hours old and have almost no claps yet. For **what works**, use **Top this month** or **Top this year**, or set **Minimum claps**.
- With **Top this year** and at least 10 claps, the `python` tag gave **403 stories in 76 seconds**: Medium shows 100 per view, the rest came from the other views and search.

### Pricing

**$0.001 per story**, plus **$0.001 per story** for the full text when you switch it on.

- 1,000 stories: **$1** (with full text **$2**)
- The run above: 1,105 stories with full text, **$2.21**

### Good to know

- **Member-only stories**: their metadata is complete; the full text is Medium's public preview only, flagged with `fullTextIsPreview`.
- **100 stories per tag view**: Medium itself shows at most 100 stories for each view of a tag. Ask for more and the scraper adds the other views and a search for the tag, so several hundred unique stories per tag are normal.
- **Authors and publications** are read newest first, all the way back.
- **Personal data**: only the public author of each story (name, username, follower count). Commenters, readers and followers are never collected.
- **Same story twice** (found by a tag and by a search) is saved and charged once.
- No login, no API key, no proxies needed.

### Input

| Field | Meaning |
|---|---|
| **Tags** | Medium tags, one per line |
| **Tag stories** | Newest, trending, top this week, month, year or of all time |
| **Search** | Searches, one per line |
| **Authors** | `@username`, `username` or profile address |
| **Publications** | `better-programming` or the publication's address |
| **Story addresses** | Single stories |
| **Maximum stories per source** | 1 to 5,000 (default 50) |
| **Full text** | Off by default |
| **Images in the full text** | On by default |
| **Minimum claps** | 0 by default |
| **Only stories from the last (days)** | 0 = any date |

### Integrations

Export to JSON, CSV, Excel or Google Sheets, or connect through the Apify API, webhooks, Make, Zapier and n8n. Schedule it daily with **Only stories from the last 1 day** to follow a topic, or send the Markdown straight into a vector database.

# Actor input Schema

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

One per line, as on medium.com/tag/...: "artificial-intelligence", "python", "startup", "self-improvement". Plain words work too ("Machine Learning").

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

Which stories of each tag: the newest, the trending ones, or the most clapped in a period.

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

Optional. One search per line, as in Medium's search box: "rag pipeline", "remote work burnout".

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

Optional. One per line: "@username", "username" or the profile address (medium.com/@username, username.medium.com). Their stories, newest first.

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

Optional. One per line: the publication's name in its address, e.g. "better-programming" for medium.com/better-programming, or its full address.

## `postUrls` (type: `array`):

Optional. Individual Medium stories to read, one address per line.

## `maxPostsPerSource` (type: `integer`):

Stops each source after this many stories that pass the filters.

## `includeFullText` (type: `boolean`):

Also read each story's full text, as Markdown and plain text. Member-only stories give the public preview only (flagged).

## `includeImagesInMarkdown` (type: `boolean`):

Keep the story's images in the Markdown.

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

Only stories with at least this many claps.

## `onlyNewerThanDays` (type: `integer`):

0 = any date.

## Actor input object example

```json
{
  "tags": [
    "artificial-intelligence"
  ],
  "tagSort": "NEW",
  "maxPostsPerSource": 50,
  "includeFullText": false,
  "includeImagesInMarkdown": true,
  "minClaps": 0,
  "onlyNewerThanDays": 0
}
```

# Actor output Schema

## `stories` (type: `string`):

One row per story: author, publication, claps, responses, reading time, tags and full text when asked for.

## `summaries` (type: `string`):

Per tag, search, author or publication: median claps, top posts, top authors and related tags.

## `csv` (type: `string`):

All stories without the full text.

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

Counts and notes.

# 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 = {
    "tags": [
        "artificial-intelligence"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("precious_bathmat/medium-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 = { "tags": ["artificial-intelligence"] }

# Run the Actor and wait for it to finish
run = client.actor("precious_bathmat/medium-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 '{
  "tags": [
    "artificial-intelligence"
  ]
}' |
apify call precious_bathmat/medium-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,precious_bathmat/medium-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/aBmFN6Hnn0Y0QXhLb/builds/uHcTuL13tSn1Uopb5/openapi.json
