# Medium Article Scraper — Articles, Tags & Authors (`junipr/medium-scraper`) Actor

Scrape public Medium articles by tag, author, publication, search, or URL with titles, authors, dates, tags, engagement, and optional content.

- **URL**: https://apify.com/junipr/medium-scraper.md
- **Developed by:** [junipr](https://apify.com/junipr) (community)
- **Categories:** News, Developer tools
- **Stats:** 2 total users, 1 monthly users, 70.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $17.19 / 1,000 medium source processeds

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/platform/actors/running/actors-in-store#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

## Medium Article Scraper — Articles, Tags & Authors

Extract public Medium RSS articles by tag, author, publication, URL, or tag-style query. Get titles, URLs, dates, tags, author data, images, word counts, and optional content as text or HTML.

### What Can You Extract?

| Field | Description |
|-------|-------------|
| `title` / `subtitle` | Article title and subtitle |
| `content` / `contentHtml` | Optional article text or HTML from the RSS feed |
| `author` | Author name, username, and profile URL when available |
| `tags` | Topic tags |
| `isMemberOnly` | Whether article is behind paywall |
| `publishedDate` | Publication date (ISO 8601) |
| `featuredImage` | Cover image URL |
| `wordCount` | Approximate word count |
| `language` | Detected language |

### How to Use

**Scrape by tag (zero-config):**

```json
{}
```

Extracts one article tagged "web-scraping" by default.

**Scrape specific articles:**

```json
{
  "articleUrls": [
    "https://medium.com/@user/article-title-abc123",
    "https://betterprogramming.pub/some-article-def456"
  ]
}
```

**Scrape by author:**

```json
{
  "authorUrls": ["https://medium.com/@towardsdatascience"],
  "maxArticlesPerSource": 10,
  "includeContent": true,
  "contentFormat": "text"
}
```

**Scrape by publication with date filters:**

```json
{
  "publicationUrls": ["https://betterprogramming.pub"],
  "dateFrom": "2025-01-01",
  "memberOnly": "free"
}
```

### Input Configuration

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `articleUrls` | array | `[]` | Direct Medium article URLs |
| `tags` | array | `["web-scraping"]` | Medium topic tags |
| `authorUrls` | array | `[]` | Author profile URLs |
| `publicationUrls` | array | `[]` | Publication homepage URLs |
| `searchQueries` | array | `[]` | Query terms mapped to Medium tag feeds |
| `maxArticlesPerSource` | integer | `1` | Max articles per tag/author/publication/query |
| `includeContent` | boolean | `false` | Extract article content from the RSS feed |
| `contentFormat` | string | `"text"` | `text` or `html` |
| `dateFrom` | string | — | Filter: only articles after this date |
| `dateTo` | string | — | Filter: only articles before this date |
| `memberOnly` | string | `"all"` | `all`, `free`, or `member_only` |
| `sortBy` | string | `"relevance"` | `relevance` or `latest` |

### Output Example

```json
{
  "url": "https://medium.com/@user/the-complete-guide-abc123",
  "articleId": "abc123",
  "title": "The Complete Guide to Web Scraping in 2026",
  "subtitle": "Everything you need to know",
  "author": {
    "name": "John Smith",
    "username": "johnsmith",
    "url": "https://medium.com/@johnsmith"
  },
  "content": "Full article text content...",
  "tags": ["web-scraping", "python", "automation"],
  "isMemberOnly": false,
  "publishedDate": "2026-02-15T10:30:00.000Z",
  "wordCount": 3200,
  "featuredImage": "https://miro.medium.com/...",
  "scrapedAt": "2026-03-11T12:00:00.000Z"
}
```

### Edge Cases

- **Member-only articles:** The RSS marker is retained; content is included only when present in the feed
- **Custom domain publications:** The actor requests the publication's `/feed` endpoint
- **Unavailable feeds:** No article rows or source event are emitted when a feed cannot be fetched
- **Non-English articles:** Unicode content is preserved; language detection is not performed

### Pricing

**$17.19 per 1,000 Medium sources processed** ($0.01719 per tag, author, publication, or article source) using the live Store pricing entry and `medium-source-processed` event. A one-time `actor-start` event is scheduled at $0.0125 per run.

Platform usage handling follows the actor's live Store pricing entry.

| Run Type | Sources | Cost |
|----------|---------|------|
| Tag research | 1 | $0.03 |
| Author archive | 10 | $0.18 |
| Publication scrape | 100 | $1.73 |
| Research batch | 1,000 | $17.20 |

### FAQ

#### Can I scrape member-only (paywalled) articles?

Titles, authors, dates, and tags are returned when present in the RSS feed. Member-only content is included only when the feed provides it; the actor does not bypass authentication.

#### What content formats are supported?

Plain text and HTML from the RSS feed.

#### Can I filter articles by date or popularity?

Use `dateFrom` and `dateTo` for date-range filtering. RSS does not expose a reliable clap count, so popularity filtering is not offered.

#### Does it work with custom domain publications?

Yes. Publications on custom domains (e.g., betterprogramming.pub) are detected as Medium via meta tags and extracted normally.

#### Can I use this for AI training data?

Text output can support downstream analysis and RAG workflows. Respect author copyright and do not republish content without permission.

***

Legal notice: Medium's ToS prohibits automated access, but article content is publicly available and indexed by search engines. Use responsibly. Do not circumvent authentication or republish scraped content.

Related actors by Junipr: [Spotify Playlist Scraper](https://apify.com/junipr/spotify-playlist) | [AI Content Detector](https://apify.com/junipr/ai-content-detector)

# Actor input Schema

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

Direct Medium article URLs to scrape.

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

Medium tags to scrape articles from (e.g. 'web-scraping', 'python', 'startup').

## `authorUrls` (type: `array`):

Medium author profile URLs (e.g. https://medium.com/@username).

## `publicationUrls` (type: `array`):

Medium publication URLs (e.g. https://betterprogramming.pub).

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

Look up Medium tag feeds derived from these query terms.

## `maxArticlesPerSource` (type: `integer`):

Maximum articles to extract per tag, author, or publication. Min: 1, Max: 1000.

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

Extract full article content.

## `contentFormat` (type: `string`):

Content output format: text or html.

## `dateFrom` (type: `string`):

Only articles published after this date (ISO 8601, e.g. 2024-01-01).

## `dateTo` (type: `string`):

Only articles published before this date (ISO 8601).

## `memberOnly` (type: `string`):

Filter by member-only status: all, free, or member\_only.

## `sortBy` (type: `string`):

Sort order for tag/search results.

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

Proxy settings for requests.

## Actor input object example

```json
{
  "articleUrls": [],
  "tags": [
    "web-scraping"
  ],
  "authorUrls": [],
  "publicationUrls": [],
  "searchQueries": [],
  "maxArticlesPerSource": 1,
  "includeContent": false,
  "contentFormat": "text",
  "memberOnly": "all",
  "sortBy": "relevance",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Article title, URL, optional text or HTML content, author, tags, member-only status, image, word count, and publication date.

# 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("junipr/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 = {}

# Run the Actor and wait for it to finish
run = client.actor("junipr/medium-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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 junipr/medium-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=junipr/medium-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

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