# Medium User Posts Scraper (`codingfrontend/medium-user-posts-scraper`) Actor

Extract detailed post data from a Medium user profile. Get article titles, descriptions, claps, reading times, and publication details.

- **URL**: https://apify.com/codingfrontend/medium-user-posts-scraper.md
- **Developed by:** [Coding Frontned](https://apify.com/codingfrontend) (community)
- **Categories:** Developer tools, Social media, Automation
- **Stats:** 3 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.99 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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 User RSS Posts Scraper

Collects public posts from one or more Medium user RSS feeds. The active entry point uses direct HTTP requests and Cheerio to parse feed-provided content; it does not launch a browser or use a proxy.

### What this Actor does

- Accepts one username or a list of usernames.
- Divides maxItems fairly across requested feeds.
- Reads the public feed at medium.com/feed/@username.
- Deduplicates posts by article URL across all requested users.
- Extracts article identity, author and publication data, feed content HTML and text, excerpts, content counts, headings, images, links, tags, timestamps, and feed metadata.

The content fields reflect what Medium publishes in the RSS feed. They can be excerpts or full feed content depending on the user feed; the Actor does not bypass paywalls or fetch protected article pages.

### Input

```json
{
  "username": "karpathy",
  "maxItems": 5
}
```

For several users:

```json
{
  "usernames": [
    "karpathy",
    "example"
  ],
  "maxItems": 10
}
```

At least one non-empty username or usernames list is required. Usernames may include a leading @ and must contain only letters, numbers, dots, underscores, or hyphens. maxItems defaults to 10 and accepts values from 1 to 200.

### Output

Each successful dataset row is one public user-feed post. Every row also includes `status`, `position`, `source`, `sourcePageUrl`, `found`, `dataAvailable`, and `success`. A failed or empty feed is stored as an explicit diagnostic row and is never shaped like a successful post.

```json
{
  "recordType": "mediumUserPost",
  "userPostRank": 1,
  "articleId": "example-post",
  "articleTitle": "An example post",
  "articleUrl": "https://medium.com/@karpathy/an-example-post",
  "articleDomain": "medium.com",
  "authorName": "Example author",
  "authorUsername": "karpathy",
  "authorProfileUrl": "https://medium.com/@karpathy",
  "contentText": "Public feed content...",
  "contentWordCount": 1200,
  "estimatedReadMinutes": 6,
  "feedUrl": "https://medium.com/feed/@karpathy",
  "sourceHttpStatus": 200,
  "extractionMethod": "medium-full-content-rss",
  "proxyConfigured": false,
  "scrapedAt": "2026-08-16T10:00:00.000Z"
}
```

Optional values are omitted when the feed does not publish them. The dataset view highlights rank, title, author, publication, excerpt, tags, publication time, and URL.

### Storage

Posts and explicit diagnostics are written to the default dataset. The fixed `OUTPUT` key reconciles dataset, success, and diagnostic counts plus the normalized usernames and run status.

### Local QA

```bash
npm test
apify run --purge --input-file qa-inputs/local-single.json
node validate-datasets.js
apify run --purge --input-file qa-inputs/local-multiple.json
node validate-datasets.js
```

### Cost and limitations

There is no external API fee. Apify compute charges may still apply. Medium can disable or change RSS feeds, return fewer items, omit metadata, or expose only excerpts.

### FAQ

#### Does this Actor scrape private or paywalled content?

No. It reads public RSS feeds only and does not authenticate or open protected article pages.

#### Why are there fewer posts than maxItems?

The feed may contain fewer entries, a feed request may fail, or duplicate URLs may be removed.

#### Can I pass a proxy?

No. The active implementation uses direct HTTP requests and reports proxyConfigured as false.

### Disclaimer

Use this Actor only where you have a lawful basis to collect and use public feed data. Respect Medium terms, RSS policies, rate limits, copyright, privacy requirements, and applicable law.

# Actor input Schema

## `username` (type: `string`):

One username with or without a leading @. Used when usernames is not supplied.

## `usernames` (type: `array`):

Optional list of usernames. When supplied, it replaces username and maxItems is divided fairly across users.

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

Maximum total unique post records across all requested users.

## Actor input object example

```json
{
  "username": "karpathy",
  "maxItems": 10
}
```

# Actor output Schema

## `dataset` (type: `string`):

Complete records parsed from public Medium user RSS feeds.

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

Fixed OUTPUT record with successful and diagnostic counts.

# 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 = {
    "username": "karpathy"
};

// Run the Actor and wait for it to finish
const run = await client.actor("codingfrontend/medium-user-posts-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 = { "username": "karpathy" }

# Run the Actor and wait for it to finish
run = client.actor("codingfrontend/medium-user-posts-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 '{
  "username": "karpathy"
}' |
apify call codingfrontend/medium-user-posts-scraper --silent --output-dataset

```

## MCP server setup

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