Substack Scraper: Posts, Full Text, Reactions & Paywall avatar

Substack Scraper: Posts, Full Text, Reactions & Paywall

Pricing

Pay per usage

Go to Apify Store
Substack Scraper: Posts, Full Text, Reactions & Paywall

Substack Scraper: Posts, Full Text, Reactions & Paywall

Scrape any Substack newsletter archive: title, subtitle, full post text, author, publish date, reactions, comment count and whether the post is behind the paywall. No login, no API key, pay per post.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

The Mine Works

The Mine Works

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

a day ago

Last modified

Share

๐Ÿ“ฐ Substack Scraper: Posts, Full Text, Reactions & Paywall

โšก Pure HTTP. No login, no API key, no proxy, no browser.

๐Ÿ’ธ You are only charged for a post that actually lands in your dataset. Publications that fail to load are never billed.

Overview

Substack Scraper turns any Substack newsletter into structured rows. Give it a publication name, a subdomain, or a full URL, and it returns every post with title, subtitle, author, publish date, word count, reaction count, comment count, the canonical URL, and the full post text.

It reads each publication's own archive endpoint, so there is nothing to log into and no key to manage. Custom domains work exactly like *.substack.com addresses.

โœ… Any publication, including custom domains ยท โœ… Free and paywalled posts identified ยท โœ… Engagement metrics per post ยท โœ… MCP-ready for AI agents

What you get that a plain RSS reader does not

Substack's public RSS feed carries roughly the last 20 posts and no engagement data at all. This actor reads the archive API instead, which means:

  • The whole back catalogue, not the last 20 posts, paginated 50 at a time.
  • Reactions and comment counts per post, so you can rank a newsletter's archive by what actually landed.
  • Paywall status on every post, via audience (everyone or only_paid) and an is_paywalled boolean.
  • Word count as Substack itself reports it.

About paywalled posts

Every post carries audience, so you always know whether it is free or paid. For paid posts Substack serves the publicly available portion, which for many publications is most of the article and for others is a short preview.

We report what we actually received rather than guessing: when the delivered text is materially shorter than the word count Substack declares, the row is flagged content_truncated: true.

We do not attempt to bypass the paywall. It is the publication's business model, breaking it would be a legal problem for you, and any such trick would break the moment Substack tightened it. If you need the full text of paid posts, subscribe to the publication.

Input

{
"publications": ["bigtechnology", "platformer.news", "https://www.astralcodexten.com/"],
"maxPostsPerPublication": 50,
"includeBody": true,
"audienceFilter": ""
}
FieldWhat it takes
publicationsA plain name (bigtechnology), a subdomain, or any full URL. Custom domains are supported.
maxPostsPerPublicationHard cap per publication. Your main cost and runtime control.
includeBodyFetch the full post text. This costs one extra request per post, see the note below. Turn it off for a fast metadata-only pass.
audienceFilterLimit to free posts, paywalled posts, or leave blank for both.

Why includeBody matters for cost. The archive endpoint returns 50 posts of metadata in a single request, but it does not include post bodies: it returns an empty body_html field at every page size. Real bodies come from the per-post endpoint, one request each. So a metadata-only run is one request per 50 posts, while a full-text run is one request per post. Both are supported; pick the one your use case needs.

Output

{
"publication": "bigtechnology",
"post_id": "209279848",
"title": "When Artificial Intelligence Is Too Valuable To Sell",
"subtitle": "The frontier labs are rethinking who gets access",
"url": "https://www.bigtechnology.com/p/when-artificial-intelligence-is-too",
"authors": ["Alex Kantrowitz"],
"published_at": "2026-07-31T19:30:17.712Z",
"post_type": "newsletter",
"audience": "only_paid",
"is_paywalled": true,
"word_count": 1139,
"reactions_total": 74,
"reactions": { "โค": 74 },
"comment_count": 0,
"body_text": "It's time to delete the assumption that the frontier AI labs will always license...",
"scraped_at": "2026-08-13T13:02:44.108Z"
}
FieldDescription
๐Ÿ“ฐ publicationPublication name
๐Ÿ”‘ post_idSubstack post ID, stable for deduplication across runs
๐Ÿ“„ title / subtitlePost headline and standfirst
๐Ÿ”— urlCanonical post URL
๐Ÿ‘ค authorsBylined authors
๐Ÿ“… published_atISO publish timestamp
๐Ÿท๏ธ post_typenewsletter, podcast, thread and so on
๐Ÿ”“ audienceeveryone (free) or only_paid (paywalled)
๐Ÿ”’ is_paywalledBoolean form of the above
๐Ÿ“ word_countWord count Substack reports for the full post
โค๏ธ reactions_totalAll reactions summed into one sortable number
๐Ÿ˜€ reactionsThe raw reaction map keyed by emoji
๐Ÿ’ฌ comment_countNumber of comments
๐Ÿ“ƒ body_textPost body as clean plain text
โœ‚๏ธ content_truncatedTrue when only part of a paid post was publicly available
๐Ÿ•’ scraped_atISO timestamp of capture

Why reactions appear twice. Substack returns reactions as a map keyed by emoji ({"โค": 74}), which is faithful but impossible to sort on. We keep the raw map and add a summed integer so you can rank an archive by engagement without writing your own reducer.

Common use cases

Newsletter competitive research. Pull a competitor's full archive, sort by reactions_total, and see exactly which topics their audience responded to.

Content and topic research. Search across the body text of a set of newsletters in your space to find who has covered a subject and how.

Author and market intelligence. Track publishing cadence, word counts and the free-versus-paid mix across publications to understand how a newsletter is monetising.

AI and RAG pipelines. Newsletter archives are dense, well-edited prose, which makes them strong retrieval material. Pull once, index, and keep current on a schedule.

Media monitoring. Watch a set of publications for mentions of a company, person or product.

Pricing

EventPriceYou pay when
Post delivered$0.0015A post lands in your dataset

$1.50 per 1,000 posts. Publications that do not exist or return nothing cost nothing.

Run it on a schedule

  1. Run once with the input you want repeated, then click Save as a task.
  2. In the Apify Console go to Schedules โ†’ Create new.
  3. Pick a frequency and attach the saved task.
  4. Wire the dataset to Sheets, Slack or a webhook from the Integrations tab.

Deduplicate on post_id so a repeated schedule never reprocesses the same post.

FAQ

Do I need a Substack account or subscription? No. The actor reads publicly available archive data. A subscription is only relevant if you want the full text of paid posts, which this actor does not bypass.

Does it work with custom domains? Yes. Many established newsletters publish from their own domain rather than *.substack.com, and both are handled.

How far back does it go? As far as the publication's archive allows, paginated 50 posts at a time up to your cap.

Why is my run slower with includeBody on? Because each post body is a separate request. See the cost note above.

Why did a paid post come back shorter than its word count? Because only part of it is public. That row is flagged content_truncated: true.

Use from Claude, ChatGPT and any MCP agent

https://mcp.apify.com/?tools=themineworks/substack-scraper

Or call it programmatically:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('themineworks/substack-scraper').call({
publications: ['bigtechnology', 'platformer.news'],
maxPostsPerPublication: 50,
includeBody: true,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

Questions, or need a field we don't return yet? Reach out through the Apify profile.