Substack Scraper (Posts, Likes, Comments, Full Text) avatar

Substack Scraper (Posts, Likes, Comments, Full Text)

Pricing

from $0.70 / 1,000 post scrapeds

Go to Apify Store
Substack Scraper (Posts, Likes, Comments, Full Text)

Substack Scraper (Posts, Likes, Comments, Full Text)

Export every post of any Substack newsletter (substack.com or custom domain): title, subtitle, date, authors, likes, comments, restacks, word count, paid or free, tags, podcast link and, optionally, the full text. Export to Excel, CSV or JSON.

Pricing

from $0.70 / 1,000 post scrapeds

Rating

0.0

(0)

Developer

Julio Barcellos Rangel

Julio Barcellos Rangel

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

22 days ago

Last modified

Categories

Security

Limited permissions

Share

Substack Scraper exports the posts of any Substack newsletter, on substack.com or on a custom domain: title, subtitle, date, authors, likes, comments, restacks, word count, free or paid, tags, podcast link and, if you want, the full text. It is built for content marketers, newsletter writers, sponsors, researchers and AI teams who want to scrape a Substack archive or export Substack posts to Excel, CSV or JSON. No login is needed.

What does Substack Scraper do?

You give it one or more newsletters and it reads each newsletter's public archive, newest posts first, until it reaches your limit or the end of the archive. Each post becomes one row with its numbers and links.

You can enter a newsletter in any of these forms:

  • A Substack name: platformer (read as platformer.substack.com)
  • A Substack address: astralcodexten.substack.com
  • A full URL or custom domain: https://www.lennysnewsletter.com

If you paste a link to a single post, the scraper uses the newsletter's main address and reads the whole archive.

Optional settings let you:

  • Add the full text of each post as plain text (for paid posts, only the free preview part).
  • Only get posts newer than a date, for example the last month, so scheduled runs only pick up new posts.

What data can you extract?

FieldWhat it meansExample
publicationNewsletter address the post comes fromhttps://www.lennysnewsletter.com
postIdSubstack post ID215694124
titlePost titleAll of the Lenny & Friends Summit talks are now online!
subtitlePost subtitlePlus, some reflections and takeaways from the day
urlLink to the posthttps://www.lennysnewsletter.com/p/all-of-the-lenny-and-friends-summit
postDatePublication date (ISO 8601)2026-09-29T13:15:57.512Z
typePost type as Substack reports itnewsletter, podcast
audienceWho can read the post, as Substack reports iteveryone, only_paid
isPaidtrue when the post is for paid (or founding) subscribers onlyfalse
authorsAuthor names on the byline["Hamel Husain", "Shreya Shankar"]
likesNumber of likes (reactions)283
commentsNumber of comments6
restacksNumber of restacks5
wordCountLength of the post in words1276
coverImageCover image URLhttps://substack-post-media.s3.amazonaws.com/public/images/…
tagsPost tags["AI"]
podcastUrlAudio file link for podcast postsnull
podcastDurationSecondsPodcast length in secondsnull
previewShort preview text of the post👋 Hey there, I’m Lenny. Each week, I share…
contentFull post text as plain text (only when Include full text is on)I’m excited to share that every main-stage talk…
contentIsPreviewtrue when content is only the free preview of a paid post (only with full text)false
scrapedAtWhen the post was scraped (ISO 8601)2026-10-10T20:36:47.536Z
inputOnly on error rows: the newsletter you enteredplatformer
errorOnly on error rows: why no posts came backPublication not found or has no posts

How to use Substack Scraper

  1. Open Substack Scraper in Apify Console.
  2. Add newsletters to Newsletters, one per line: a name such as platformer, an address such as name.substack.com, or a custom domain URL.
  3. Set Max posts per newsletter (default 50). Use a high number to export the whole archive.
  4. Optional: pick a date in Only posts newer than to skip older posts.
  5. Optional: turn on Include full text to add the post body.
  6. Click Start and wait for the run to finish.
  7. Open the Output tab and export the posts as JSON, CSV, Excel or HTML.

Input

FieldTypeDefaultWhat it does
publicationslist of text (required)["https://www.lennysnewsletter.com"]Substack names, URLs or custom domains, for example platformer, https://www.lennysnewsletter.com, astralcodexten.substack.com.
maxPostsPerPublicationinteger50Maximum posts per newsletter, newest first. From 1 to 10,000.
includeContenttrue/falsefalseAdds content (post text as plain text) and contentIsPreview. For paid posts you only get the free preview.
onlyPostsNewerThandate (YYYY-MM-DD)emptyOnly returns posts published on or after this date. The scraper stops reading the archive when it reaches an older post.
proxyobject{ "useApifyProxy": true }Apify Proxy settings. The default works for most runs.

Example input:

{
"publications": ["https://www.lennysnewsletter.com", "platformer"],
"maxPostsPerPublication": 200,
"includeContent": true,
"onlyPostsNewerThan": "2026-01-01",
"proxy": { "useApifyProxy": true }
}

Output example

One real post from a recent run:

{
"publication": "https://www.lennysnewsletter.com",
"postId": 215694124,
"title": "All of the Lenny & Friends Summit talks are now online!",
"subtitle": "Plus, some reflections and takeaways from the day",
"url": "https://www.lennysnewsletter.com/p/all-of-the-lenny-and-friends-summit",
"postDate": "2026-09-29T13:15:57.512Z",
"type": "newsletter",
"audience": "everyone",
"isPaid": false,
"authors": ["Lenny Rachitsky"],
"likes": 283,
"comments": 6,
"restacks": 5,
"wordCount": 1276,
"coverImage": "https://substack-post-media.s3.amazonaws.com/public/images/9fed347c-0e02-4190-a590-1236719b99de_9213x6142.jpeg",
"tags": [],
"podcastUrl": null,
"podcastDurationSeconds": null,
"preview": "👋 Hey there, I’m Lenny. Each week, I share deeply researched product, growth, and career advice. For more: Lenny’s Jobs | Lennybot | Become an AI-Native Builder and other favorite AI/PM courses",
"scrapedAt": "2026-10-10T20:36:47.536Z"
}

With Include full text on, the same post also gets these two fields (text trimmed):

{
"content": "👋 Hey there, I’m Lenny. Each week, I share deeply researched product, growth, and career advice…\n\nI’m excited to share that every main-stage talk from the recent Lenny & Friends Summit is now online…",
"contentIsPreview": false
}

How much does it cost?

Substack Scraper uses pay-per-event pricing. You pay $1.00 per 1,000 posts ($0.001 per post) on the Free plan. Apify platform usage is included in the price, and the full text does not cost extra.

PlanPrice per 1,000 posts
Free$1.00
Bronze (-10%)$0.90
Silver (-20%)$0.80
Gold and higher (-30%)$0.70

Worked examples on the Free plan:

  • The latest 50 posts of one newsletter = $0.05
  • A full archive of 1,000 posts with full text = $1.00
  • 20 newsletters, 500 posts each = 10,000 posts = $10.00

What you are not charged for:

  • Error rows: newsletters that could not be found, have no posts, or were not a valid address.
  • Posts skipped by the Only posts newer than date.
  • Duplicate posts: a post that shows up twice in the archive is returned once.

Use cases

  • Content research: find the most liked, commented and restacked posts of a newsletter and see which topics work.
  • Competitor analysis: compare posting frequency, post length and paid versus free posts across newsletters in your niche.
  • Sponsorship research: check engagement before you buy a sponsored slot in a newsletter.
  • AI and RAG datasets: export full post text to build a searchable knowledge base, summaries or training data (respect the authors' rights).
  • Monitoring: schedule a daily run with Only posts newer than to get new posts from the newsletters you follow.
  • Podcast catalogs: list podcast episodes with audio links and durations.
  • Academic and media research: study what writers publish on Substack over time.

Tips and limits

  • Paid posts: without a subscription you only get the free preview part. isPaid and contentIsPreview tell you when the text is incomplete. wordCount is still the length of the full post.
  • Full text is slower: with Include full text on, the scraper may load each post separately to get its body, so large archives take longer.
  • Empty text: if one post's text cannot be loaded, its content is an empty string and the run continues.
  • Date filter: the archive is read newest first and the scraper stops at the first post older than your date. If no post is newer than the date, you get an error row (Publication not found or has no posts), which is free.
  • Numbers are a snapshot: likes, comments and restacks are the counts at the time of the run. Schedule runs to track them over time.
  • Custom domains: newsletters on their own domain work the same as name.substack.com.
  • Enter each newsletter once: duplicates are not merged, so platformer and platformer.substack.com in the same run scrape (and charge) the newsletter twice.
  • Error rows: Invalid publication URL means the text could not be read as an address; Publication not found or has no posts means the archive was empty, not found or did not answer after four tries.

Use it from the API, Python or JavaScript

You can run the scraper and read the posts with the official Apify clients. Replace YOUR_TOKEN with your Apify API token.

JavaScript (Node.js):

const { ApifyClient } = require('apify-client');
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const input = { publications: ['https://www.lennysnewsletter.com'], maxPostsPerPublication: 100 };
const run = await client.actor('juliob.rangel/substack-scraper-fast').call(input);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);

Python:

from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')
input = {'publications': ['https://www.lennysnewsletter.com'], 'maxPostsPerPublication': 100}
run = client.actor('juliob.rangel/substack-scraper-fast').call(run_input=input)
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)

The scraper also works with Make, Zapier and n8n, can export results to Google Sheets, can call your webhook when a run finishes, and can be used by AI agents through the Apify MCP server.

FAQ

Do I need a Substack account or login? No. The scraper reads the public archive of each newsletter. It does not log in, so paid posts only include their free preview.

Can I export Substack posts to Excel or CSV? Yes. Open the Output tab after the run and download the dataset as Excel, CSV, JSON or HTML, or send it to Google Sheets.

How many posts can I get? Up to 10,000 per newsletter in one run, limited by how many posts the newsletter has published.

Does it work with custom domains? Yes. Enter the domain (for example https://www.lennysnewsletter.com) and the scraper reads it like any substack.com newsletter.

Can I get the comments themselves? No. You get the number of comments per post (comments), not the comment text.

Is it legal to scrape Substack? The scraper only collects publicly available data. You are responsible for complying with Substack's terms, copyright and privacy laws such as GDPR and LGPD. Post text belongs to its authors, and author names are personal data, so you need a legitimate reason to collect and use them.

Why did I get an error row? The newsletter address was not valid, the newsletter has no posts, or Substack did not answer. If you used Only posts newer than, it can also mean there are no posts after that date. Error rows are not charged.


Extrator do Substack (PT-BR)

Exporte todos os posts de qualquer newsletter do Substack: título, data, autores, curtidas, comentários, restacks, se é pago e, se quiser, o texto completo. Funciona com substack.com e domínios próprios. Você paga só por post retornado.