Medium Scraper — Articles, Full Text, Authors, Claps & Comments
Pricing
from $1.00 / 1,000 results
Medium Scraper — Articles, Full Text, Authors, Claps & Comments
Scrape Medium by tag, search, author, publication or URL: posts with claps, responses, reading time, tags, author and publication stats, plus optional full article text as Markdown and comments. Whole tag archives, thousands of posts per run, no login. Not affiliated with Medium.
Pricing
from $1.00 / 1,000 results
Rating
0.0
(0)
Developer
Logiover
Maintained by CommunityActor stats
0
Bookmarked
1
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
Medium Scraper
Medium Scraper is a fast Medium article scraper and a practical Medium API alternative. Scrape Medium posts, claps, responses (comments), reading time, tags, authors and publications without login, cookies or a Medium account — by tag, by keyword search, by author, by publication or from any Medium URL — and export the Medium data to CSV, Excel, JSON, XML or Google Sheets. Turn on one switch and every story also comes with its full article text as clean Markdown and plain text, ready for AI, RAG and LLM pipelines.
Use it as a Medium tag scraper (the complete newest-first archive of any tag, not just the 10 stories an RSS feed shows), a Medium author scraper (every story a writer has published, plus their follower count and bio), a Medium publication scraper (any publication, custom domains such as levelup.gitconnected.com included), a Medium search scraper (posts, people, publications or tags for any keyword) and a Medium comments scraper (responses and reply threads with full text). Measured on 2026-10-13: 10,000 posts in 40 seconds, the entire history of a tag (4,840 posts back to 2018) in 34 seconds, and 1,000 posts in under 10 seconds.
Medium Scraper is an independent tool. It is not affiliated with, endorsed by or sponsored by Medium (A Medium Corporation). See the disclaimer.
What you get
One run can mix several sources. Every row has a rowType, so posts, responses and profiles can live in one dataset and be filtered or exported separately (the Dataset tab has a ready-made view for each).
| Row type | One row per | Main fields |
|---|---|---|
post | Medium story | title, subtitle, URL, canonical URL, published / updated date, reading time, word count, claps, clappers, responses count, tags, member-only flag, language, preview image, author (name, username, followers, bio, member status, X/Twitter), publication (name, slug, URL, followers), rank, source |
post + full text | Medium story with includeContent | everything above plus article text (plain), Markdown (headings, lists, quotes, code blocks with language, links, images), image URLs, outbound links, code-block and paragraph counts, preview flag |
response | response (comment) or reply | full text, claps, clappers, replies count, depth (1 = response, 2 = reply …), parent and root post IDs, root post URL, author name / username / followers, date |
author | writer | name, username, profile URL, bio, followers, following, photo, member since, membership tier, Partner Program, book-author badge, X/Twitter, custom domain |
publication | publication | name, slug, URL, custom domain, description, followers, logo, X/Twitter, topics, owner, editors and editor count |
tag | tag / topic | name, slug, URL, total posts in the tag, followers |
71 documented fields, typed in the dataset schema, with consistent empty values (null, never 0 for "unknown").
Why this Medium scraper
- No login, no cookies, no browser. It reads the same data Medium's own web app loads for signed-out visitors. Nothing to configure, nothing to get banned.
- Real depth. Tags are read from Medium's complete chronological tag archive — every story ever tagged, newest first — not from a ranked list that stops at ~100. Authors and publications are read back to their first story.
- Fast. Big sources are read in parallel time slices and delivered strictly newest-first: 1,000 posts in 6–10 s, 10,000 in 40 s.
- Full article text as Markdown and plain text with one switch, at no extra request cost (the text rides along with each page of posts).
- Comments too. Responses and reply threads, with full text, claps and authors.
- Exact limits.
maxItemsis honoured to the row — you never get (or pay for) more rows than you asked for. Duplicates are removed across all sources in a run. - Honest run status. A tag, author or publication that does not exist ends the run as Succeeded with a clear message ("tag … does not exist on Medium"), not as a mysterious failure. A run fails only when Medium could not be reached at all.
- Built-in reliability. Fresh connection per request, automatic retries and hedged requests, automatic fallback to Apify Proxy if Medium ever refuses direct requests, and a time budget that always leaves room to save your data before the run's timeout.
- Fresh data. Everything is fetched live at run time — claps, follower counts and responses are as of the minute you run it.
Use cases
Content research and topic discovery
Pull the newest 5,000 stories of artificial-intelligence, product-management or web3 and see what people write about, which angles get claps, which subtitles work, how long successful posts are (wordCount, readingTimeMinutes) and which tags travel together.
Competitor and blog monitoring
Track a competitor's engineering blog or a publication in your niche. Schedule the Actor daily with publishedAfter: "1 day" and get only the new stories, with claps and responses, in your inbox, Slack or Google Sheet.
Writer and influencer discovery
Search people for "data engineering" or scrape the top lists of a tag to find the writers your audience reads — with follower counts, bios, X/Twitter handles, Partner Program status and their full story history. Great for outreach lists, guest-post sourcing and creator marketing.
AI, RAG and LLM datasets
Collect clean article text and Markdown (code blocks keep their language) with authors, dates, tags and canonical URLs for retrieval-augmented generation, semantic search, summarisation or classification. Use skipMemberOnly to keep only stories whose complete text is public, and language: "en" to keep one language.
Trend analysis and market intelligence
Measure how a topic grows: posts per day in a tag, average claps, share of member-only stories, top publications, top authors. Because the tag archive is chronological and complete, publishedAfter / publishedBefore give exact time windows (a whole month of a busy tag is cheap).
SEO and content-gap analysis
Search Medium for your keywords, export titles, subtitles and tags, and find the questions your blog has not answered yet.
How it works
- Inputs are normalised. Tag names,
@usernames, profile URLs, publication slugs, custom domains, story URLs and search URLs are all recognised automatically. - Medium's own data endpoint is queried — the GraphQL API medium.com's web app uses: exact clap counts, IDs and timestamps, not HTML that changes with every redesign.
- Chronological sources are read in parallel time slices. The first page measures how many stories per hour a tag, author or publication produces; the time range that should hold your
maxItemsis then cut into small slices that up to 16 lanes read at once. Rows are released strictly newest-first, so when the run reachesmaxItemsyou still have exactly the newest N stories, andrank1 is the newest. - Ranked lists and search are paged in parallel and delivered in Medium's own order (
rank= position). - Responses are fetched for many posts per request, best first, with optional reply threads.
- Every row is checked against the dataset schema, de-duplicated across sources and counted before it is written, so
maxItemsis exact even with 20 requests in flight. - A SUMMARY record (key-value store) lists rows per type, notes such as "author @x not found", and why the run stopped (
stoppedBy:MAX_ITEMS,MAX_COST,TIMEOUTor none).
Quick start
- Open the Actor and type a tag into Tags, e.g.
artificial-intelligence(that is the prefilled example). - Set Max rows (100 for a test, 10,000+ for a real export).
- Click Start. Rows appear in the Dataset tab within a few seconds. Export as CSV, Excel, JSON, XML or HTML, or connect the run to Google Sheets, Make, Zapier or n8n.
Prefilled example (finishes in about 4 seconds):
{"tags": ["artificial-intelligence"],"tagSort": "newest","maxItems": 100,"proxyConfiguration": { "useApifyProxy": true }}
Input reference
| Field | Type | Default | What it does |
|---|---|---|---|
tags | list | — | Tags as slugs, names or URLs: artificial-intelligence, Machine Learning, https://medium.com/tag/python. |
tagSort | select | newest | newest = complete chronological archive (unlimited depth). trending, top-week, top-month, top-year, top-all-time = Medium's ranked lists (~100 each). all-top = all ranked lists combined. |
searchQueries | list | — | Keywords for Medium search, one per line. |
searchType | select | posts | What the queries search: posts, people, publications or tags. |
authors | list | — | @username, username, https://medium.com/@name or https://name.medium.com. Returns the profile and all stories, newest first. |
publications | list | — | Slug (better-programming), URL (https://medium.com/swlh) or custom domain (levelup.gitconnected.com). Returns the publication and all its stories. |
startUrls | list | — | Any Medium URL: story (also on custom domains), tag page, profile, publication, or search page (https://medium.com/search?q=rust). Story IDs work too. |
maxItems | number | 1000 | Total rows for the run (posts + responses + profile rows). 0 = no limit. |
maxPostsPerSource | number | 0 | Cap per tag / author / publication / query, so one big source cannot use up the run. 0 = no cap. |
publishedAfter | text | — | Only stories published on/after this date: 2025-01-01, 2025-01-01T12:00:00Z, or relative 30 days, 6 months, 1 year. Chronological sources stop reading here. |
publishedBefore | text | — | Only stories published before this date (same formats). Chronological sources start reading here. |
minClaps | number | 0 | Skip stories with fewer claps. |
language | text | — | Keep only these languages, ISO codes comma-separated: en or en, es, pt. |
skipMemberOnly | yes/no | no | Leave out member-only (paywalled) stories. |
includeContent | yes/no | no | Add article text (plain + Markdown), image URLs, links, code-block count. |
includeResponses | yes/no | no | Add responses (comments) of every collected story as response rows. |
maxResponsesPerPost | number | 50 | Responses (and replies) per story, best first. 0 = all. |
includeReplies | yes/no | no | Follow reply threads under responses (depth 2, 3 …). |
includeProfiles | yes/no | yes | Add one profile row for each tag, author and publication you list. |
maxConcurrency | number | 20 | Requests in flight (1–50). |
proxyConfiguration | proxy | Apify Proxy | Default: direct connection (fastest) with automatic switch to Apify Proxy if Medium refuses. Pick a proxy group or your own proxies to force them. |
Examples for every mode
Newest stories of several tags (complete archive):
{ "tags": ["artificial-intelligence", "startup", "javascript"], "maxItems": 5000 }
A precise time window — every English story in a tag during January 2025 with at least 50 claps:
{"tags": ["machine-learning"],"publishedAfter": "2025-01-01","publishedBefore": "2025-02-01","minClaps": 50,"language": "en","maxItems": 0}
Medium's best stories of a topic (trending + top week / month / year / all time):
{ "tags": ["productivity"], "tagSort": "all-top", "maxItems": 500 }
Keyword search for posts:
{ "searchQueries": ["rust async", "vector database"], "searchType": "posts", "maxItems": 2000 }
Find writers (people search):
{ "searchQueries": ["data engineering", "growth marketing"], "searchType": "people", "maxItems": 1000 }
Every story of some authors, with their profiles:
{ "authors": ["@ev", "https://medium.com/@devrimozcay"], "maxItems": 0 }
A whole publication (custom domains work):
{ "publications": ["levelup.gitconnected.com", "better-programming"], "maxPostsPerSource": 2000, "maxItems": 4000 }
Specific stories with full text and comments:
{"startUrls": ["https://medium.com/ai-engineering-simplified/5-claude-tricks-that-give-you-an-unfair-advantage-most-people-still-use-the-old-way-0385a58057c7","https://levelup.gitconnected.com/macos-never-got-the-file-manager-developers-deserved-so-i-built-it-e8ac81480578"],"includeContent": true,"includeResponses": true,"includeReplies": true,"maxResponsesPerPost": 0}
An AI / RAG corpus — free stories only, full text, one language:
{"tags": ["llm", "retrieval-augmented-gen", "prompt-engineering"],"includeContent": true,"skipMemberOnly": true,"language": "en","maxItems": 10000}
Daily monitoring (schedule this every morning):
{ "tags": ["your-niche-tag"], "publications": ["competitor-publication"], "publishedAfter": "1 day", "maxItems": 0 }
Output data dictionary
Post rows (rowType: "post")
| Field | Type | Description |
|---|---|---|
id | string | Medium story ID (12 hex characters). Stable — use it to de-duplicate across runs. |
title, subtitle | string | Headline and the subtitle / preview line Medium shows in feeds. |
url | string | Story URL (the publication's custom domain when it has one). |
canonicalUrl | string | Canonical link; differs from url when the story was first published elsewhere. |
publishedAt, updatedAt | ISO date | First publication and latest published edit (UTC). |
readingTimeMinutes | number | Medium's reading-time estimate. |
wordCount | number | Words in the full story (also for member-only stories). |
claps, voters | number | Total claps and number of distinct readers who clapped. |
responsesCount | number | Number of responses (comments). |
tags | string | Tag slugs, pipe-separated (ai | startup | productivity). |
isMemberOnly, visibility | boolean, string | Paywall flag; PUBLIC, LOCKED or UNLISTED. |
language | string | Detected language (ISO 639-1). |
previewImageUrl | string | Feature image, 1200 px wide. |
isShortform | boolean | Medium short-form post. |
authorId, authorName, authorUsername, authorUrl | string | The writer. |
authorBio, authorFollowers, authorFollowing, authorImageUrl | mixed | Writer's bio, followers, following, photo. |
authorIsMember, authorTwitter | boolean, string | Paying Medium member; X/Twitter handle. |
publicationId, publicationName, publicationSlug, publicationUrl, publicationFollowers | mixed | Publication the story appeared in (empty for personal-profile stories). |
contentText, contentMarkdown | string | Article body (with includeContent). Member-only stories: the public preview. |
contentIsPreview | boolean | true when the body is the paywall preview, false when it is the complete story. |
contentImageUrls, contentLinks | string | Images and outbound links / embeds inside the article, pipe-separated. |
codeBlockCount, paragraphCount | number | Code blocks and paragraphs in the body. |
source | string | Which input produced the row: tag:<slug>, tag:<slug>/top-week, search:<query>, author:<username>, publication:<slug>, url. |
rank | number | Position in its source: search rank, position in a ranked list, or 1 = newest for chronological sources. |
scrapedAt | ISO date | Collection time. |
Response rows (rowType: "response")
| Field | Type | Description |
|---|---|---|
id, url | string | Response ID and URL (responses are small Medium stories). |
text | string | Full response text. |
publishedAt, updatedAt | ISO date | When it was written / edited. |
claps, voters, repliesCount | number | Claps, clappers, replies under it. |
depth | number | 1 = response to the story, 2 = reply to a response, … |
parentPostId, rootPostId, rootPostUrl | string | What it answers, and the story the thread belongs to. |
authorId, authorName, authorUsername, authorUrl, authorFollowers | mixed | Who wrote it. |
Author rows (rowType: "author")
id, name, username, url, bio, followers, following, imageUrl, isMember, memberSince, membershipTier (MEMBER / FRIEND), isPartnerProgram, isBookAuthor, twitter, customDomain, source, rank (search results only), scrapedAt.
Publication rows (rowType: "publication")
id, name, slug, url, domain, description, followers, imageUrl, twitter, tags, creatorName, creatorUsername, editors, editorsCount, source, rank (search results only), scrapedAt.
Tag rows (rowType: "tag")
id (slug), name, url, postCount (total stories in the tag), followers, source, rank (search results only), scrapedAt.
Example output
Real rows from test runs on 2026-10-13 (article text shortened here).
Post with full text (tags: ["productivity"], tagSort: "top-all-time", includeContent: true):
{"rowType": "post","id": "5f26de35b84c","title": "You Shouldn’t Be Prompting AI Anymore. You Should Be Designing Loops.","subtitle": "Peter Steinberger built one of the fastest-growing open-source projects in history by doing something most developers were too busy to…","url": "https://aiadvances.org/you-shouldnt-be-prompting-ai-anymore-you-should-be-designing-loops-5f26de35b84c","canonicalUrl": "https://aiadvances.org/you-shouldnt-be-prompting-ai-anymore-you-should-be-designing-loops-5f26de35b84c","publishedAt": "2026-06-09T14:14:08.695Z","updatedAt": "2026-06-09T14:14:08.695Z","readingTimeMinutes": 11,"wordCount": 2853,"claps": 379,"voters": 87,"responsesCount": 9,"tags": "software-development | artificial-intelligence | programming | productivity | technology","isMemberOnly": false,"visibility": "PUBLIC","language": "en","previewImageUrl": "https://miro.medium.com/v2/resize:fit:1200/1*FpjCUf87cdd6H5sedbi0bg.png","isShortform": false,"authorId": "106212946ead","authorName": "Aftab","authorUsername": "aftab001x","authorUrl": "https://medium.com/@aftab001x","authorBio": "AI","authorFollowers": 381,"authorFollowing": 2,"authorImageUrl": "https://miro.medium.com/v2/resize:fit:400/1*6EU4UFLYSEtZqDugnds7tQ.jpeg","authorIsMember": false,"authorTwitter": null,"publicationId": "3fe99b2acc4","publicationName": "AI Advances","publicationSlug": "ai-advances","publicationUrl": "https://aiadvances.org","publicationFollowers": 113201,"contentText": "You Shouldn’t Be Prompting AI Anymore. You Should Be Designing Loops.\n\nPeter Steinberger built one of the fastest-growing open-source projects in history by doing something most developers were too busy to notice: he stopped talki …","contentMarkdown": "### You Shouldn’t Be Prompting AI Anymore. You Should Be Designing Loops.\n\n\n\nPeter Steinberger built one of the fastest-growing open-source projects in hi …","contentIsPreview": false,"contentImageUrls": "https://miro.medium.com/v2/resize:fit:1400/1*FpjCUf87cdd6H5sedbi0bg.png","contentLinks": null,"codeBlockCount": 0,"paragraphCount": 72,"source": "tag:productivity/top-all-time","rank": 50,"scrapedAt": "2026-10-13T10:37:17.858Z"}
Response (comment):
{"rowType": "response","id": "ad76cb0bf1bf","url": "https://medium.com/@libbyswinkler/there-are-good-recommendations-here-many-i-have-not-yet-consumed-ad76cb0bf1bf","text": "There are good recommendations here—many I have not yet consumed. I am saving this as a reading list. Thanks!","publishedAt": "2026-06-14T16:00:37.474Z","updatedAt": "2026-06-14T16:00:37.474Z","claps": 96,"voters": 37,"repliesCount": 1,"depth": 1,"parentPostId": "eed8d14f3bee","rootPostId": "eed8d14f3bee","rootPostUrl": "https://medium.com/the-useful-life/8-books-you-should-definitely-read-at-least-once-in-your-life-eed8d14f3bee","authorId": "af03698341e7","authorName": "Healthy Me Happy Me","authorUsername": "libbyswinkler","authorUrl": "https://medium.com/@libbyswinkler","authorFollowers": 727,"source": "tag:productivity/top-all-time","scrapedAt": "2026-10-13T10:37:18.225Z"}
Author profile (authors: ["@ev"]):
{"rowType": "author","id": "268314bb7e7e","name": "Ev Williams","username": "ev","url": "https://medium.com/@ev","bio": "Curious human, cofounder @ Mozi, chairman @ Medium, partner @ Obvious Ventures","followers": 213261,"following": 2699,"imageUrl": "https://miro.medium.com/v2/resize:fit:400/1*Oa7aZoW8TPZrQjlKYzH5dg.jpeg","isMember": true,"memberSince": "2017-02-13T19:37:08.000Z","membershipTier": "FRIEND","isPartnerProgram": true,"isBookAuthor": false,"twitter": null,"customDomain": "ev.medium.com","source": "author:ev","scrapedAt": "2026-10-13T10:27:19.303Z"}
Publication profile (publications: ["levelup.gitconnected.com"]):
{"rowType": "publication","id": "5517fd7b58a6","name": "Level Up Coding","slug": "gitconnected","url": "https://levelup.gitconnected.com","domain": "levelup.gitconnected.com","description": "Coding tutorials and news. The developer homepage gitconnected.com && skilled.dev && levelup.dev","followers": 365226,"imageUrl": "https://miro.medium.com/v2/resize:fit:400/1*5D9oYBd58pyjMkV_5-zXXQ.jpeg","twitter": "gitconnected","tags": "programming | artificial intelligence | software engineering","creatorName": "Trey Huffine","creatorUsername": "treyhuffine","editors": "treyhuffine | warlyware","editorsCount": 2,"source": "publication:levelup.gitconnected.com","scrapedAt": "2026-10-13T10:27:18.690Z"}
How much data can I get?
Measured on the Apify platform on 2026-10-13:
| Source | How deep it goes | Measured |
|---|---|---|
Tag, newest | The whole tag history. Medium keeps a complete chronological archive per tag. | rust-programming-language: 4,840 posts — every story back to Nov 2018 (Medium's own count: 4,830) in 34 s. programming: 10,000 posts in 40 s (the newest 15 days of a tag that gets ~330 posts a day). |
| Tag, ranked lists | ~100 posts per list (Medium's limit); all-top combines five lists. | startup, all-top: 287 unique top posts in 4.5 s. |
| Search, posts | ~1,000 results per query (Medium's limit). Add more queries for more. | "rust" + "product management": 1,000 posts in 6.1 s. |
| Search, people / tags | ~1,000 per query. | "data science" people: 300 writers in 4.8 s. |
| Search, publications | ~500 per query. | — |
| Author | Every story since the account started. | Ev Williams: all 121 stories back to Aug 2012 in 3.5 s; two authors, 1,000 rows in 9.7 s. |
| Publication | Every story in the publication. | Level Up Coding: 1,000 posts in 8.2 s. |
| Responses | All responses and replies of a story (maxResponsesPerPost: 0). | 100 top stories + 1,899 responses and replies in 8.2 s. |
Need tens of thousands of rows? Add more tags (each tag's archive is complete and independent), widen the date window, combine tags with searches, authors and publications, and set maxItems to 0 or a large number. Duplicates across sources are removed automatically. A 10,000-row run is routine.
Big runs and "Maximum cost per run". Every pay-per-event run on Apify has a maximum cost — the one you set in the run options, or the platform's default. Medium Scraper reads it at the start and plans for exactly the number of results it covers. If you ask for 20,000 rows but the run's maximum cost covers 11,000, it saves 11,000, ends as Succeeded and says so in the status message ("Saved 11000 results — this run's maximum cost ($…) covers 11000 results at the current price. Raise "Maximum cost per run" to get more."). It never fails or gets aborted for this. For 10,000+ rows, set "Maximum cost per run" to at least rows × price per result (Pricing tab).
Speed and resources per 1,000 rows
All measured on 2026-10-13, default settings:
| Run | Rows | Time | Peak memory |
|---|---|---|---|
| Prefilled example (tag, 100 rows) | 100 | 4.2 s | 54 MB |
Tag artificial-intelligence, newest | 1,000 | 8.7 s | 60 MB |
Tag programming, newest | 10,000 | 39.8 s | 111 MB |
| Two tags with full article text | 10,000 | 103 s | 216 MB |
| Search, 2 queries | 1,000 | 6.1 s | 53 MB |
| Publication | 1,000 | 8.2 s | 60 MB |
| Responses + replies | 2,000 | 8.2 s | 60 MB |
- Metadata-only runs: about 4 s per 1,000 posts at scale.
- With full article text: about 10 s per 1,000 posts; the text comes in the same requests, so it costs time and memory, not extra requests.
- Memory: 1 GB default (it gives the run more CPU for article text); 512 MB is plenty for metadata-only runs.
- No residential proxy needed. No browser.
- What you pay: a fixed price per result — see the Pricing tab (on 2026-10-13: $1.50 per 1,000 results on the Free plan, down to $1.00 per 1,000 from the Gold plan up). Compute, storage and proxies are included; there is no separate proxy bill and no subscription.
Integrations
Run it from the API (cURL)
curl -X POST "https://api.apify.com/v2/acts/logiover~medium-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \-H "Content-Type: application/json" \-d '{"tags":["artificial-intelligence"],"maxItems":100}'
Returns the rows as a JSON array. For long runs use the asynchronous /runs endpoint.
Node.js
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('logiover/medium-scraper').call({tags: ['startup'],includeContent: true,maxItems: 500,});const { items } = await client.dataset(run.defaultDatasetId).listItems();console.log(items.filter((r) => r.rowType === 'post').map((r) => `${r.claps}\t${r.title}`).join('\n'));
Python
from apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run = client.actor("logiover/medium-scraper").call(run_input={"authors": ["@ev"],"includeResponses": True,"maxItems": 1000,})for row in client.dataset(run["defaultDatasetId"]).iterate_items():if row["rowType"] == "post":print(row["publishedAt"], row["claps"], row["title"])
Make, Zapier, n8n
Use the Apify app in Make, Zapier or n8n ("Run an Actor" → logiover/medium-scraper, then "Get dataset items"), e.g. new stories in a tag → Slack; a competitor publication → Notion or Airtable; scheduled daily with publishedAfter: "1 day".
Google Sheets
Export the dataset as CSV, or use Apify's Google Sheets integration to append every run's rows to a sheet automatically — ideal for a living content-research tracker.
Webhooks
Add a "Run succeeded" webhook and fetch https://api.apify.com/v2/datasets/{datasetId}/items?format=csv (or json, xlsx).
AI agents and MCP
Through Apify's MCP server, AI agents (Claude, ChatGPT, Cursor and other MCP clients) can call logiover/medium-scraper as a tool: "find the 50 most-clapped posts about RAG this month and summarise them". The Markdown output is ready for LLM context windows and RAG chunking.
Medium Scraper vs other ways to get Medium data
| Medium Scraper | Medium RSS feeds | Copy-paste by hand | Generic browser scrapers | |
|---|---|---|---|---|
| Stories per tag | Complete archive (thousands) | Latest ~10 | As many as you can stand | Usually the first screen |
| Claps, clappers, responses count | Yes | No | Manually | Sometimes |
| Search (posts / people / publications / tags) | Yes | No | Yes, slowly | Rarely |
| Comments (responses + replies) | Yes, full text | No | Manually | Rarely |
| Author & publication stats (followers, bio, editors) | Yes | Partial | Manually | Sometimes |
| Full article text as Markdown | Yes (free stories complete) | Partial HTML | Yes | HTML only |
| Speed | 10,000 posts in ~40 s | — | Hours | Seconds per page |
| Login / cookies needed | No | No | No | Often |
| Export | CSV, Excel, JSON, XML, Sheets, API | XML | — | Varies |
Limits and tips
- Member-only stories: Medium shows signed-out readers only the beginning of a paywalled story, and that is what you get (
contentIsPreview: true). Titles, claps, word count and all metadata are complete. UseskipMemberOnlywhen you need complete text only. This Actor does not bypass the paywall. - Ranked lists and search have Medium's own ceilings (~100 per ranked list, ~1,000 per search query, ~500 per publication search). For more, use
tagSort: "newest"(unlimited) or add queries. - Order: chronological sources are numbered newest-first in
rank; rows can land in the dataset slightly out of order because they are written in parallel — sort byrankorpublishedAtif order matters. - Exact limits:
maxItemscounts every row (posts, responses and profile rows). Turn offincludeProfilesif you want posts only. - Fewer rows than
maxItemsmeans the sources ran out (e.g. an author with 120 stories), your filters excluded the rest, or duplicates across sources were removed. The run's status message and SUMMARY say which. - Date filters are cheap on chronological sources — the scraper starts and stops reading at your dates instead of filtering afterwards.
FAQ
Do I need a Medium account, login or cookies?
No. The Actor only reads what Medium shows to signed-out visitors. You never share credentials.
Is there an official Medium API for this?
Medium's official API was built for publishing stories and does not offer tag archives, search, claps or responses. This Actor is the practical Medium API alternative for reading public data, with a stable JSON output.
How many posts can I scrape from one tag?
All of them. tagSort: "newest" walks the complete tag archive back in time — measured 4,840 of 4,830 counted posts for rust-programming-language (the whole history since 2018) and 10,000 posts of programming in 40 seconds.
Can I get the full text of member-only (paywalled) stories?
You get the public preview Medium shows to signed-out readers, flagged with contentIsPreview: true. Free stories come complete (contentIsPreview: false). The Actor does not bypass the paywall.
How do I scrape all stories of a Medium author?
Put their @username or profile URL into Authors and set maxItems to 0. You get one profile row and every story, newest first. Custom subdomains like name.medium.com work too.
How do I scrape a Medium publication?
Put the slug (swlh for The Startup), URL or custom domain (levelup.gitconnected.com) into Publications. You get the publication's profile (followers, editors, description) and its stories, newest first.
Can I scrape Medium comments?
Yes — enable Include responses. Each response is a row with full text, claps, author and reply count; Include replies follows the threads below them. maxResponsesPerPost limits per story (0 = all).
How do I get only new stories since my last run?
Schedule the Actor with publishedAfter: "1 day" (or "6 hours", "1 week"). Use id to de-duplicate across runs.
How do I export Medium data to CSV, Excel or Google Sheets?
Open the run's Dataset tab and choose CSV, Excel, JSON, XML or HTML — or use the Google Sheets integration or the API URL with format=csv / format=xlsx. Pick a view (Posts, Article text, Responses, Authors, Publications, Tags) to export only those columns.
Why did I get fewer rows than maxItems?
The sources were exhausted (a small tag, an author with few stories, a search limit), your filters removed stories, the same story came from two sources and was kept once, or the run's Maximum cost per run covered fewer results. The run is still Succeeded; its status message and SUMMARY (stoppedBy) explain.
My big run stopped with a "maximum cost" message — what do I do?
Pay-per-event runs have a maximum cost per run (yours or the platform default). The scraper stops cleanly at the number of results that budget covers instead of being aborted. Raise Maximum cost per run in the run options (or maxTotalChargeUsd in the API) to at least rows × price per result and run again.
What happens if a tag, author or publication does not exist?
The run finishes as Succeeded with a message such as tag "xyz" does not exist on Medium, so your automation does not break. Other valid sources in the same run are scraped normally.
Do I need a proxy?
No setup needed. By default the Actor connects directly (fastest) and switches to Apify Proxy automatically if Medium ever refuses direct requests. You can force a specific proxy group in the input.
What does rank mean?
For search and ranked lists it is Medium's position; for chronological sources (tag archive, author, publication) it numbers stories newest-first, so rank: 1 is the newest story of that source.
Can I use the data to train AI models or build a RAG app?
The text of every story belongs to its author. Analysis, search indexes, summaries and internal research are common uses; republishing or training on copyrighted text may need permission depending on your jurisdiction and purpose. See the legality section below.
How fast is it really?
Measured 2026-10-13: 100 rows in 4 s, 1,000 posts in 6–10 s, 10,000 posts in 40 s, 10,000 posts with full article text in 103 s.
What if Medium changes something?
The Actor reads structured data from Medium's own web app endpoint, which changes far less often than page layouts. Runs report problems clearly instead of silently returning nothing, and issues are fixed fast — see support below.
Is it legal to scrape Medium?
This Actor collects only publicly available data that Medium shows to any signed-out visitor; it does not log in, does not bypass the paywall and does not collect private information. Web scraping of public data is generally lawful, but you are responsible for how you use the results:
- Personal data (names, bios, social handles) may be protected by GDPR, CCPA and similar laws. Have a legitimate purpose and store only what you need.
- Copyright: stories and responses belong to their authors. Quote, analyse and link responsibly; do not republish full articles without permission.
- Respect Medium's terms and reasonable request volumes.
If in doubt, consult a lawyer about your specific use case.
Changelog
- 2026-10-13 — first release. Tag archive (complete history), ranked tag lists, search (posts / people / publications / tags), authors, publications, story URLs, full article text as Markdown + plain text, responses with reply threads, author / publication / tag profile rows, date / claps / language / paywall filters, parallel time-sliced reading (10,000 posts in 40 s), exact
maxItems, honest run outcomes, automatic proxy fallback.
Full history in the Changelog tab.
Support
Found a bug, need a field or a new source? Open an issue on the Issues tab — we answer within 24 hours. Please include the run ID so we can look at the exact run.
Disclaimer
Medium Scraper is an independent tool and is not affiliated with, endorsed by or sponsored by Medium or A Medium Corporation. "Medium" is a trademark of A Medium Corporation and is used here only to describe the website this tool works with. Use the data in line with applicable laws and Medium's terms.