Substack Scraper - Publication Posts, Reactions & Paywall avatar

Substack Scraper - Publication Posts, Reactions & Paywall

Pricing

from $0.25 / 1,000 posts

Go to Apify Store
Substack Scraper - Publication Posts, Reactions & Paywall

Substack Scraper - Publication Posts, Reactions & Paywall

Substack scraper for the posts in a publication's archive, one row each: title, link, date, authors, word count, comments, reactions, restacks and whether it sits behind the paywall. No account or cookies. No article text, which the archive does not publish. $0.26 per 1,000 posts.

Pricing

from $0.25 / 1,000 posts

Rating

0.0

(0)

Developer

Dami's Studio

Dami's Studio

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

5 days ago

Last modified

Share

Give it a Substack handle and get the publication's archive back, one row per post: title, link, date, author, word count, comments, reactions, restacks, and whether the post sits behind the paywall. A handle like astralcodexten is enough.

Read this before you buy: no row carries the article text. A publication's public archive does not publish post bodies, for free posts either, so there is nothing to hand you. What you do get is audience, the real free-or-paid flag, and Substack's own short preview on roughly half of publications.

InputSubstack handles or domains, up to 20 per run
OutputOne row per post: title, link, date, authors, word count, comments, reactions, restacks and the paywall flag
Ceiling2,000 posts per publication, 20 publications per run
SpeedRoughly 800 to 950 posts a minute, measured on runs of 400 and 1,474 posts
Account neededNone, no cookies, no browser
Price$0.26 per 1,000 posts on the Free plan, a little less on paid plans. The free plan's $5 a month covers about 19,000

🔍 What Substack Publication Scraper does

It reads a publication's own archive and walks it to the depth you ask for. A handle on its own is enough. If the publication moved onto its own domain, give that domain: a publication on its own domain only answers there, and its old substack.com address hands back an empty archive rather than an error.

You can point it at 20 publications in one run, and each gets its own post budget, so one prolific newsletter cannot eat the whole run.

A word on what arriving means. Three different wrong answers all come back looking like success: a publication that has moved returns an empty list, one redirects to a profile page, and a site that is not Substack at all serves its own page from the same address. Each of those is caught and turned into an uncharged row that says what to do about it. Nothing is billed for an answer that was not an archive.

📋 What data you get from each Substack post

What you getField
The publication, the post title and its subtitlepublication, title, subtitle, description
The canonical link, slug and Substack's post idurl, slug, postId
When it was publishedpostDate
Free or paid, in Substack's words and as a booleanaudience, isPaywalled
Substack's own short preview, when it has onepreviewText
Word count of the full postwordCount
Comments, reactions and restackscommentCount, reactionCount, restackCount
Every bylineauthors
Newsletter, podcast, thread and so onpostType
Cover image and languagecoverImage, language

▶️ How to scrape a Substack archive

  1. Open Substack Publication Scraper and click Try for free.
  2. Put one handle per line into Substack publications.
  3. Set Posts per publication. Start around 10 while you are looking at the output shape.
  4. Pick an Order if reverse date order is not what you want.
  5. Click Start, then download the dataset as JSON, CSV or Excel, or read it from the Apify API.

💰 How much does it cost to scrape Substack?

$0.26 per 1,000 posts on the Free plan. Paid plans pay a little less: $0.258 on Starter, $0.256 on Scale and $0.254 on Business. On the free plan, the $5 Apify gives you each month covers about 19,000 posts.

You pay per post row delivered. Duplicates, the sample row and diagnostic rows are free, and a publication that returns nothing writes a free row instead of posts.

📥 What you give it

{
"publications": ["astralcodexten", "www.bigtechnology.com"],
"maxPostsPerPublication": 50,
"sort": "new"
}
FieldDefaultWhat it is
publicationsnoneOne per line, up to 20. A bare handle works, so does a full address. Give the publication's own domain if it has one. The form opens with astralcodexten and www.bigtechnology.com.
maxPostsPerPublication50Posts to take from each publication, 1 to 2,000. A publication with fewer simply returns fewer. This is also your spending cap.
sortnewnew is the archive in reverse date order, top is the publication's most popular, community puts discussion threads first.
proxyUrlsnoneOptional. Your own servers, one URL per line as http://user:pass@host:port. Leave it empty for a normal run.

📤 What you get back

A real row from a real run:

{
"ok": true,
"charged": true,
"recordType": "post",
"publication": "astralcodexten.substack.com",
"title": "Your Book Review: This Is Going To Hurt",
"url": "https://www.astralcodexten.com/p/your-book-review-this-is-going-to",
"postDate": "2026-09-18T20:53:58.344Z",
"audience": "everyone",
"isPaywalled": false,
"subtitle": "Finalist #9 in the Book Review Contest",
"description": "Finalist #9 in the Book Review Contest",
"previewText": null,
"wordCount": 12639,
"commentCount": 295,
"reactionCount": 152,
"restackCount": 7,
"authors": "Scott Alexander",
"postType": "newsletter",
"slug": "your-book-review-this-is-going-to",
"postId": "216363681",
"coverImage": "https://substack-post-media.s3.amazonaws.com/public/images/916daf3c-...png",
"language": "en",
"scrapedAt": "2026-09-21T02:09:44.003Z"
}
FieldHow to read it
postIdSubstack's own id. Stable, so use it to dedupe across runs.
audienceeveryone or only_paid, straight from Substack. isPaywalled is that same fact as a boolean.
previewTextPresent on some publications and null on others, as above. It is not the article.
wordCountSubstack's count for the full post, including the part you cannot read.
authorsEvery byline joined with commas, or null when the post has none.
restackCountSubstack restacks, its own share count.
urlThe canonical link, which is the publication's own domain when it has one.

🧾 Reading the output

Three kinds of row can land in your dataset, and recordType tells them apart.

RowHow to spot itBilled
A postrecordType: "post"yes
The sample row_sample: true, recordType: "sample"no
A diagnostic_diagnostic: true and an errorCodeno

The charged field is a label on the row, not a receipt. It is stamped when the row is built, before billing happens, so treat it as the same signal as recordType: it separates real posts from the sample and diagnostic rows, nothing more.

CodeWhat it means
NOT_FOUNDNo Substack publication answers at that address. Check the spelling, or use the publication's own domain.
NO_RESULTSThe address answered but returned no posts, which is what a publication that has moved to its own domain does.
TIME_BUDGETThe run ran out of time before reaching that publication. Everything already delivered is complete.
RATE_LIMITEDSubstack asked the run to slow down and it gave up on that item. Re-run it.
NOT_SERVEDThis post was not served this run. Re-run it later. Runs before 13 October 2026 wrote BLOCKED here.
SERVER_ERRORSubstack returned a server error. Usually passes on its own.
NETWORKSubstack was unreachable. Re-run it.
PROXY_INPUT_ADJUSTEDA connection setting in your input was not usable, so the run used its own.
CHARGE_ERRORBilling could not be recorded for some rows. Rare, and worth telling us about.

One bad publication never stops the others, and a diagnostic row never fails the run. The one exception is an unexpected error on our side before anything came back: that run ends as failed, with an UNEXPECTED_ERROR row.

💡 What people use it for

  • Tracking which posts a newsletter puts behind the paywall and which it leaves open, using audience over time.
  • Ranking a publication's back catalogue by reactionCount or commentCount to see what actually landed.
  • Pulling 20 newsletters in one field into a single sheet to compare posting cadence.
  • Watching a competitor's publishing rhythm on a schedule, deduped on postId.

🚧 What it does not do

  • No article text. The archive does not publish post bodies. previewText is Substack's own snippet, and plenty of publications never fill it.
  • No subscriber counts, no revenue, no email list size. None of that is public.
  • No comments themselves, only how many there are.
  • A publication on its own domain only answers on that domain. Its old substack.com address returns an empty archive, and you will get a row saying so.
  • top and community are Substack's own orderings, so asking for 20 of them gives you the 20 it serves first.
  • No Substack Notes, no podcasts beyond the post record, and no cross-publication search.
  • Rows are a snapshot. Reaction and comment counts move, and scrapedAt records when they were read.
  • Up to 20 publications per run. Split a longer list across runs.
  • It is not an official Substack tool. Dami's Studio is independent and is not affiliated with or endorsed by Substack, or by any other company named on this page.

🧭 Which news scraper do you need?

If you wantUse
Posts in a Substack publication's archiveThis one
DEV.to articles by tag or authorDEV.to Scraper
News articles by keyword, with the publisher's real linkGoogle News Scraper
World news by keyword, in 65+ languagesGDELT News Scraper
Hacker News stories and commentsHacker News Scraper

❓ Questions people ask

Do I need a Substack account?

No. No account, no cookies, no browser.

Can I get the post text?

No. Substack's public archive does not carry post bodies, for free posts or paid ones.

How do I know if a Substack post is paywalled?

isPaywalled, or audience if you want Substack's own wording. Every row has it.

What do I put in for a publication on its own domain?

That domain. www.bigtechnology.com, not the old substack.com address, which answers empty.

Can I call it from code or connect it to an AI assistant?

The API tab has code for Python, JavaScript and the CLI. MCP clients like Claude and ChatGPT use https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/substack-publication-scraper; coding assistants can load our skill file. All three bill your Apify account at the same price.

These are public archive pages. Rows carry author names, which is personal data under GDPR, so have a reason for collecting it. Apify's write-up on the legality of web scraping is a sensible starting point, and we are not lawyers.

🆘 If something breaks

Open the Issues tab on the actor page. Send the run ID and the publication you used. The errorCode on the diagnostic row usually names the problem on its own.