# Medium Articles Scraper (`datacach/medium-scraper`) Actor

Extract Medium articles by keyword at scale — no account needed. Returns title, author, publication, clap count, reading time, tags, and direct URLs as structured JSON.

- **URL**: https://apify.com/datacach/medium-scraper.md
- **Developed by:** [DataCach](https://apify.com/datacach) (community)
- **Categories:** News, Social media, Other
- **Features:** Limited permissions
- **Stats:** 70 total users, 11 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.99 / 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 Article Scraper

**Extract articles, authors, and publication data from [Medium](https://medium.com) by keyword — no account required.** Search Medium at scale and collect rich metadata for every result: title, URL, author, publication, clap count, reading time, tags, and more. Try it directly on the [Apify platform](https://apify.com/actors) without writing a single line of code.

### What does Medium Article Scraper do?

The Medium Article Scraper lets you **search Medium for articles by keyword** and collect structured data for each result. You provide one or more search terms and a result limit; the scraper handles pagination automatically and delivers each article as a clean JSON record ready to export or integrate.

It retrieves data that is **publicly visible on Medium's search page** — no login, cookies, or API key needed.

### Why use Medium Article Scraper?

Medium does not offer a public search API, making it hard to extract content data at scale. This scraper solves that. Common use cases:

- **Content research** — Find the top-performing articles on any topic to inform your editorial strategy.
- **Competitive analysis** — Monitor what your competitors or industry leaders are publishing.
- **SEO & keyword research** — Discover trending titles, subtitles, and tags for any search term.
- **Lead generation** — Identify authors and publications active in your niche.
- **Data journalism** — Analyse publishing trends, clap counts, and reading times across topics.
- **Training datasets** — Collect article metadata for NLP or recommendation models.

Running on the Apify platform gives you scheduling, monitoring, cloud storage, and integrations with 1,500+ tools (Zapier, Make, Google Sheets, etc.) out of the box.

### How to use Medium Article Scraper

1. **Open the Actor** on [Apify Console](https://console.apify.com/actors) and click **Try for free**.
2. In the **Input** tab, enter your search keywords (e.g. `python`, `machine learning`).
3. Set **Max Results per Keyword** — how many articles you want per keyword.
4. Click **Start** and wait a few seconds.
5. Go to the **Output** tab to preview results, or click **Export** to download as JSON, CSV, or Excel.

You can also run the scraper via the [Apify API](https://docs.apify.com/api/v2) or schedule it to run automatically on a cron.

### Input

Configure the scraper in the **Input** tab or via JSON:

| Field | Type | Description | Default |
|-------|------|-------------|---------|
| `search_keywords` | Array of strings | Keywords to search for on Medium. Each keyword is scraped independently. | `["python", "docker"]` |
| `max_results` | Integer | Maximum number of articles to collect **per keyword**. Total output ≤ keywords × max_results. | `100` |
| `start_page` | Integer | Page number to start scraping from for each keyword. Useful to skip already-collected results or resume from a specific offset. | `1` |

**Example input:**

```json
{
  "search_keywords": ["machine learning", "kubernetes", "python"],
  "max_results": 50,
  "start_page": 3
}
```

This would return up to 150 articles (50 per keyword), starting from page 3 of each keyword's search results.

### Output

Each article is saved as a JSON object in the Apify dataset. You can download the dataset in **JSON, CSV, Excel, or XML** from the Output tab or via the API.

**Example output record:**

```json
{
  "title": "How a Few Great Python Libraries Helped Me Build Faster and Think Bigger",
  "mediumUrl": "https://blog.stackademic.com/how-a-few-great-python-libraries-helped-me-build-faster-and-think-bigger-3e65d5d95a23",
  "visibility": "LOCKED",
  "isPublished": true,
  "isLocked": true,
  "clapCount": 34,
  "readingTime": 5.47,
  "firstPublishedAt": 1778302377518,
  "extendedPreviewContent": {
    "subtitle": "Automation Changed Everything"
  },
  "creator": {
    "name": "Muhummad Zaki",
    "username": "Muhummadzaki"
  },
  "collection": {
    "name": "Stackademic",
    "domain": "blog.stackademic.com",
    "subscriberCount": 83405
  },
  "tags": [
    { "displayTitle": "Python" },
    { "displayTitle": "Data Science" }
  ]
}
```

### Data Fields

| Field | Type | Description |
|-------|------|-------------|
| `title` | String | Article title |
| `mediumUrl` | String | Direct URL to the article |
| `uniqueSlug` | String | Unique URL-friendly identifier |
| `visibility` | String | `LOCKED` (members only) or `PUBLIC` |
| `isPublished` | Boolean | Whether the post is live |
| `isLocked` | Boolean | Whether the post requires a Medium membership |
| `isSeries` | Boolean | Whether the post belongs to a series |
| `clapCount` | Number | Total claps received |
| `readingTime` | Number | Estimated reading time in minutes |
| `firstPublishedAt` | Number | Unix timestamp (ms) of first publication |
| `latestPublishedAt` | Number | Unix timestamp (ms) of last update |
| `pinnedAt` | Number | Unix timestamp (ms) if pinned, else `0` |
| `creator` | Object | Author details: `name`, `username`, `imageId` |
| `collection` | Object | Publication details: `name`, `domain`, `description`, `subscriberCount` |
| `tags` | Array | List of tags with display titles |
| `extendedPreviewContent` | Object | Article subtitle and preview flag |
| `previewImage` | Object | Preview image metadata |
| `postResponses` | Object | Number of responses/comments |

### Tips and Advanced Options

**Large keyword lists**
For broad research campaigns, prefer fewer keywords with a higher `max_results` value over many keywords with a low limit — you'll get more consistent, deeper coverage per topic.

**Scheduling recurring runs**
Use Apify's built-in scheduler to run the scraper daily or weekly and monitor trending articles in your niche over time.

**Exporting to Google Sheets / Zapier / Make**
Connect the dataset directly from the Apify Console **Integrations** tab — no code required.

**Crash recovery**
If a run is interrupted, restarting it automatically resumes from where it left off rather than starting over, saving both time and compute costs.

### FAQ, Disclaimers, and Support

**Is scraping Medium legal?**
This scraper only accesses data that is **publicly visible** on Medium's search results — the same data any user sees without logging in. It does not bypass paywalls, access member-only content, or collect personal data beyond what Medium displays publicly. Always comply with [Medium's Terms of Service](https://policy.medium.com/medium-terms-of-service-9db0094a1e0f) and applicable data protection laws in your jurisdiction.

**Why are some articles marked `isLocked: true`?**
Medium marks paywalled articles (requiring a membership to read in full) as `LOCKED`. The scraper collects their metadata but does not access the full article body.

**The scraper returned fewer results than expected.**
Medium's search index does not always return the maximum number of results for every query. Niche keywords may have fewer matching articles in total. Try broader keywords or verify the result count by searching manually on Medium.

**Can I scrape a specific publication or author?**
Not directly — the current version searches by keyword only. Reach out if you need filtering by publication, author, or date range.

**Found a bug or need a custom feature?**
Open an issue in the [Issues tab](https://console.apify.com/actors) on Apify, or reach out for a custom scraping solution.

# Actor input Schema

## `search_keywords` (type: `array`):

One or more keywords to search for on Medium. Each keyword is scraped independently up to the Max Results limit.

## `max_results` (type: `integer`):

Maximum number of articles to collect per keyword. Total output will be at most (keywords × max_results) items.

## `start_page` (type: `integer`):

Page number to start scraping from for each keyword. Use this to resume from a specific offset or skip already-collected results. Defaults to 1 (the beginning).

## Actor input object example

```json
{
  "search_keywords": [
    "python",
    "docker"
  ],
  "max_results": 100,
  "start_page": 1
}
```

# Actor output Schema

## `dataset` (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 = {
    "search_keywords": [
        "python",
        "docker"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("datacach/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 = { "search_keywords": [
        "python",
        "docker",
    ] }

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

```

## MCP server setup

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