# Substack Posts Scraper: Whole Archive & Comments (`luzivanlt/substack-posts-scraper`) Actor

Every post of a Substack newsletter, back to its first, with its subscriber count and paid plans. $1 per 1,000 posts. Full text and whole comment threads on request.

- **URL**: https://apify.com/luzivanlt/substack-posts-scraper.md
- **Developed by:** [Luzi](https://apify.com/luzivanlt) (community)
- **Categories:** News, Social media, Lead generation
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 90.9% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 posts

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Substack Posts Scraper: Whole Archive & Comments

Get every post of a Substack newsletter, newest first, all the way back to its
first post: title, subtitle, dates, audience (free or paid), word count,
likes, reactions, comment and restack counts, authors, tags, cover image,
podcast and audio details, and the publication's own details: its subscriber
count as Substack shows it, its paid plans and prices, and its sections and
contributors. 124 fields a post. Turn on post text for each post's full body, and comments for its whole
comment thread, replies included. Works with publications on their own
domain. No Substack account needed.

Tested daily on a sample of two newsletters. Latest full read: 4,142 posts
from three whole newsletters in about three minutes, every post each one
lists, its sections and podcast included.

### What does this Actor do?

You give it Substack newsletters: a publication's link, a writer's profile, or
a post's link. For each publication it reads the archive from the newest post
back, and saves one row per post until it reaches your limit, your date, or
the publication's first post.

Each post comes with:

- its link, id, title, subtitle, description, type (newsletter, podcast,
  thread or video) and when it was published
- who can read it (everyone or paying subscribers) and how many words it has
- its likes, each reaction's count, how many comments and replies it has, and
  how many times it was restacked
- every author: name, handle, photo, bio, X (Twitter) name, bestseller tier,
  and the publications they write for
- its tags, its section, its cover image and the image's colours
- for a podcast: the audio link, length, episode and season numbers
- the publication's name, link, own domain, logo, tagline, owner, when it
  started and its first post
- the publication's subscriber count and paid-subscriber range, as Substack
  shows them, its paid plans with their prices, what each plan offers, its
  podcast, sections and contributors

With **Include post text** on, each post also gets:

- its full body, as HTML and as plain text (a paid post gives the free
  preview only)
- when it was last updated, and the posts before and after it

With **Include comments** on, each post also gets its whole comment thread,
replies included, in reading order: each comment's text, date, likes, the
commenter's name, handle and photo, whether they are the author, and the
comment it answers.

### Why use it?

- **The whole archive.** It keeps going to a publication's very first post,
  or stops at your limit or your date. Posts filed in sections the
  publication keeps off its main archive page (a podcast, a weekly digest)
  are read too.
- **Subscribers and prices.** Every row carries the publication's subscriber
  count and paid plans, so one export compares newsletters.
- **Every comment, not a sample.** With comments on, a post's whole thread
  comes back, replies at every depth, in the post's own row.
- **One price.** The same price per post with or without the text and the
  comments; no start fee.
- **Any Substack.** Publications on substack.com and on their own domain, a
  writer's profile, or single posts.
- **Use the data anywhere.** Download as JSON, CSV or Excel, or send it to
  your own tools through Apify's API and integrations.

### How to use it

1. Paste one or more newsletters into **Substack links**:
   `https://example.substack.com`, a publication's own domain such as
   `https://www.lennysnewsletter.com`, a writer's profile
   (`https://substack.com/@handle`), or a post's link (`…/p/post-name`) for
   that one post.
2. Optionally, set **Only posts newer than**, **Max posts per publication**,
   **Include post text** and **Include comments**.
3. Click **Start**. When the run ends, open the **Output** tab to view the
   posts or download them.

Run it with no input to see a sample: up to 50 posts each from two
newsletters, charged as usual.

### Input

| Field                                                    | What it does                                                                                                  | Default |
| -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ------- |
| **Substack links** (`startUrls`)                         | Publications, writers' profiles or posts to read. Required.                                                   | —       |
| **Only posts newer than** (`onlyPostsNewerThan`)         | A date (`YYYY-MM-DD`, UTC) or a period (`7 days`, `2 weeks`, `3 months`, `1 year`). Empty = the whole archive | empty   |
| **Max posts per publication** (`maxPostsPerPublication`) | Stop reading a publication after this many posts, from 1 to 50,000                                            | `100`   |
| **Include post text** (`includeBody`)                    | Also read each post's full text                                                                               | off     |
| **Include comments** (`includeComments`)                 | Also read each post's whole comment thread                                                                    | off     |
| **Only new posts** (`onlyNewItems`)                      | Return only the posts an earlier run did not; see New items only below                                        | off     |

Example input:

```json
{
  "startUrls": ["https://www.lennysnewsletter.com", "https://noahpinion.substack.com"],
  "onlyPostsNewerThan": "6 months",
  "maxPostsPerPublication": 1000,
  "includeBody": true
}
```

### New items only

Turn on **Only new posts** (`onlyNewItems`) for a scheduled run, or a re-run
of the same task. Each run then returns only the posts it has not returned
before: it reads each publication back to a day before the last run that read
it, and skips the posts an earlier run saved. Skipped posts are neither saved
nor charged; each new post is charged as usual.

- Runs with other settings, or from another task, keep their own list, so two
  schedules on one publication never skip each other's posts.
- If a publication stops at **Max posts per publication**, the posts past
  that point are not returned later. Set the maximum above what one
  publication gets between runs.
- A post's comments are read when the post is new; comments added after that
  are not read again.
- The list lives in your Apify account, in a key-value store named
  `substack-posts-scraper-monitor`. Delete it to start afresh.

### Output

One row per post. An example, shortened, with made-up values:

```json
{
  "post_id": 900000001,
  "url": "https://example.substack.com/p/made-up-post",
  "slug": "made-up-post",
  "title": "A made-up post",
  "subtitle": "What a made-up subtitle says",
  "type": "newsletter",
  "audience": "everyone",
  "is_paid": false,
  "published_at": "2026-10-20T12:00:00.000Z",
  "word_count": 1850,
  "author_name": "Made-up Writer",
  "author_handle": "madeupwriter",
  "reaction_count": 245,
  "reactions": { "❤": 245 },
  "comment_count": 31,
  "restack_count": 12,
  "tags": [{ "id": "a1b2", "name": "Essays", "slug": "essays" }],
  "body_text": "The post's text, as plain text.",
  "publication_name": "Made-up Newsletter",
  "publication_url": "https://example.substack.com",
  "body_read": true,
  "comments_read": true,
  "comments": [
    {
      "comment_id": 5001,
      "parent_id": null,
      "depth": 0,
      "body": "A made-up comment.",
      "posted_at": "2026-10-20T14:00:00.000Z",
      "name": "Made-up Reader",
      "handle": "madeupreader",
      "is_author": false,
      "reaction_count": 4
    }
  ],
  "source_url": "https://example.substack.com"
}
```

Every field:

| Field                                    | What it holds                                                                                                                                                                                                                                                                                                                                            |
| ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `post_id`                                | Substack's id for the post                                                                                                                                                                                                                                                                                                                               |
| `url`                                    | The post on its publication                                                                                                                                                                                                                                                                                                                              |
| `slug`                                   | The post's name in its link                                                                                                                                                                                                                                                                                                                              |
| `title`                                  | The title                                                                                                                                                                                                                                                                                                                                                |
| `subtitle`                               | The subtitle                                                                                                                                                                                                                                                                                                                                             |
| `description`                            | The post's short description, as shared                                                                                                                                                                                                                                                                                                                  |
| `social_title`                           | The title shown when the post is shared, when the writer set one                                                                                                                                                                                                                                                                                         |
| `search_engine_title`                    | The title for search engines, when the writer set one                                                                                                                                                                                                                                                                                                    |
| `search_engine_description`              | The description for search engines, when the writer set one                                                                                                                                                                                                                                                                                              |
| `type`                                   | `newsletter`, `podcast`, `thread` or `video`                                                                                                                                                                                                                                                                                                             |
| `audience`                               | Who can read it: `everyone`, `only_paid`, `founding` or `only_free`                                                                                                                                                                                                                                                                                      |
| `is_paid`                                | `true` for a post only paying subscribers can read in full                                                                                                                                                                                                                                                                                               |
| `published_at`                           | When it was published                                                                                                                                                                                                                                                                                                                                    |
| `updated_at`                             | When it was last updated (body on, or a post link)                                                                                                                                                                                                                                                                                                       |
| `language`                               | The post's language code                                                                                                                                                                                                                                                                                                                                 |
| `word_count`                             | How many words it has, paid part included                                                                                                                                                                                                                                                                                                                |
| `author_id`                              | The first author's Substack id                                                                                                                                                                                                                                                                                                                           |
| `author_name`                            | The first author's name                                                                                                                                                                                                                                                                                                                                  |
| `author_handle`                          | The first author's handle (substack.com/@handle)                                                                                                                                                                                                                                                                                                         |
| `authors`                                | Every author: id, name, handle, photo, bio, X (Twitter) name, guest or not, bestseller tier, subscriber tier, badge, when the profile was set up, their own publication, and the publications they write for with their role                                                                                                                             |
| `reaction_count`                         | How many likes (hearts) it has                                                                                                                                                                                                                                                                                                                           |
| `reactions`                              | Each reaction with its count                                                                                                                                                                                                                                                                                                                             |
| `comment_count`                          | How many comments it has, replies included                                                                                                                                                                                                                                                                                                               |
| `child_comment_count`                    | How many of those are replies                                                                                                                                                                                                                                                                                                                            |
| `restack_count`                          | How many times it was restacked                                                                                                                                                                                                                                                                                                                          |
| `tags`                                   | Its tags: id, name and slug                                                                                                                                                                                                                                                                                                                              |
| `section_id`                             | The section it is filed in, when the publication has sections                                                                                                                                                                                                                                                                                            |
| `section_name`                           | That section's name                                                                                                                                                                                                                                                                                                                                      |
| `section_slug`                           | That section's name in its link                                                                                                                                                                                                                                                                                                                          |
| `is_section_pinned`                      | `true` when it is pinned in its section                                                                                                                                                                                                                                                                                                                  |
| `cover_image_url`                        | The cover image's link                                                                                                                                                                                                                                                                                                                                   |
| `cover_image_is_square`                  | `true` when the cover image is square                                                                                                                                                                                                                                                                                                                    |
| `cover_image_is_explicit`                | `true` when the cover image is marked explicit                                                                                                                                                                                                                                                                                                           |
| `cover_image_palette`                    | The cover image's main colours, as RGB values                                                                                                                                                                                                                                                                                                            |
| `truncated_body_text`                    | The post's opening lines, when the publication shows them in its archive                                                                                                                                                                                                                                                                                 |
| `body_html`                              | The post's body as HTML (body on, or a post link). For a paid post, the free preview                                                                                                                                                                                                                                                                     |
| `body_text`                              | The same body as plain text                                                                                                                                                                                                                                                                                                                              |
| `has_dynamic_content`                    | `true` when the body has parts that change for each reader                                                                                                                                                                                                                                                                                               |
| `post_preview_limit`                     | How much of a paid post is shown free                                                                                                                                                                                                                                                                                                                    |
| `should_send_free_preview`               | `true` when free subscribers got a preview by email                                                                                                                                                                                                                                                                                                      |
| `free_unlock_required`                   | `true` when a free subscriber must unlock it                                                                                                                                                                                                                                                                                                             |
| `teaser_post_eligible`                   | Substack's flag for posts that may be shown as a teaser                                                                                                                                                                                                                                                                                                  |
| `meter_type`                             | How the paywall counts reads, when the post has one (body on, or a post link)                                                                                                                                                                                                                                                                            |
| `exempt_from_archive_paywall`            | `true` when it stays free after the publication's archive goes paid (body on, or a post link)                                                                                                                                                                                                                                                            |
| `write_comment_permissions`              | Who may comment: `everyone`, `paid` or `none`                                                                                                                                                                                                                                                                                                            |
| `default_comment_sort`                   | The comment order the writer chose, when they chose one                                                                                                                                                                                                                                                                                                  |
| `podcast_url`                            | The episode's audio link, for a podcast post                                                                                                                                                                                                                                                                                                             |
| `podcast_duration`                       | The episode's length in seconds                                                                                                                                                                                                                                                                                                                          |
| `podcast_art_url`                        | The episode's own artwork (body on, or a post link)                                                                                                                                                                                                                                                                                                      |
| `podcast_episode_number`                 | The episode number                                                                                                                                                                                                                                                                                                                                       |
| `podcast_season_number`                  | The season number                                                                                                                                                                                                                                                                                                                                        |
| `podcast_episode_type`                   | `full`, `trailer` or `bonus`                                                                                                                                                                                                                                                                                                                             |
| `free_podcast_url`                       | The free preview's audio link, for a paid episode                                                                                                                                                                                                                                                                                                        |
| `free_podcast_duration`                  | The free preview's length in seconds                                                                                                                                                                                                                                                                                                                     |
| `podcast_upload_id`                      | Substack's id for the episode's audio                                                                                                                                                                                                                                                                                                                    |
| `podcast_preview_upload_id`              | Substack's id for the episode's free preview                                                                                                                                                                                                                                                                                                             |
| `video_upload_id`                        | Substack's id for the post's video                                                                                                                                                                                                                                                                                                                       |
| `voiceover_upload_id`                    | Substack's id for the writer's own reading of the post                                                                                                                                                                                                                                                                                                   |
| `has_voiceover`                          | `true` when the writer recorded a reading of the post                                                                                                                                                                                                                                                                                                    |
| `audio_items`                            | The post's audio versions (Substack's read-aloud and others): type, voice, status and link                                                                                                                                                                                                                                                               |
| `restacked_post_id`                      | For a restack: the original post's id                                                                                                                                                                                                                                                                                                                    |
| `restacked_post_slug`                    | For a restack: the original post's slug                                                                                                                                                                                                                                                                                                                  |
| `restacked_publication_name`             | For a restack: the original post's publication                                                                                                                                                                                                                                                                                                           |
| `restacked_publication_logo_url`         | That publication's logo                                                                                                                                                                                                                                                                                                                                  |
| `previous_post_slug`                     | The slug of the publication's post before it (body on, or a post link)                                                                                                                                                                                                                                                                                   |
| `next_post_slug`                         | The slug of the post after it (body on, or a post link)                                                                                                                                                                                                                                                                                                  |
| `is_published`                           | `true` for a published post (body on, or a post link)                                                                                                                                                                                                                                                                                                    |
| `is_hidden`                              | `true` when the writer hid it from the publication's home page                                                                                                                                                                                                                                                                                           |
| `is_geoblocked`                          | `true` when it is blocked in some countries                                                                                                                                                                                                                                                                                                              |
| `country_blocks`                         | The countries it is blocked in                                                                                                                                                                                                                                                                                                                           |
| `has_cashtag`                            | `true` when it mentions a stock by its $ symbol                                                                                                                                                                                                                                                                                                          |
| `has_shareable_clips`                    | `true` when it has video or audio clips readers can share (body on, or a post link)                                                                                                                                                                                                                                                                      |
| `live_stream_id`                         | The live stream it came from, when it did (body on, or a post link)                                                                                                                                                                                                                                                                                      |
| `publication_id`                         | Substack's id for the publication                                                                                                                                                                                                                                                                                                                        |
| `publication_name`                       | The publication's name                                                                                                                                                                                                                                                                                                                                   |
| `publication_url`                        | The publication's home page, on its own domain when it has one                                                                                                                                                                                                                                                                                           |
| `publication_subdomain`                  | The publication's name in its substack.com address                                                                                                                                                                                                                                                                                                       |
| `publication_custom_domain`              | The publication's own domain, when it has one                                                                                                                                                                                                                                                                                                            |
| `publication_logo_url`                   | The publication's logo                                                                                                                                                                                                                                                                                                                                   |
| `publication_hero_text`                  | The publication's tagline                                                                                                                                                                                                                                                                                                                                |
| `publication_type`                       | `newsletter` or `podcast`                                                                                                                                                                                                                                                                                                                                |
| `publication_created_at`                 | When the publication was created                                                                                                                                                                                                                                                                                                                         |
| `publication_first_post_date`            | When the publication's first post was published                                                                                                                                                                                                                                                                                                          |
| `publication_language`                   | The publication's language code                                                                                                                                                                                                                                                                                                                          |
| `publication_subscribers`                | The publication's subscriber count as Substack shows it ("Over 1,200,000 subscribers"), when the writer shows it                                                                                                                                                                                                                                         |
| `publication_subscribers_rounded`        | The same count, rounded as Substack shows it ("1.2M+")                                                                                                                                                                                                                                                                                                   |
| `publication_subscribers_range`          | Substack's range for all its subscribers, free and paid ("Millions of subscribers")                                                                                                                                                                                                                                                                      |
| `publication_subscribers_range_min`      | That range's lower end as a number (1000000)                                                                                                                                                                                                                                                                                                             |
| `publication_paid_subscribers_range`     | Substack's range for its paid subscribers ("Tens of thousands of paid subscribers"), when it shows one                                                                                                                                                                                                                                                   |
| `publication_paid_subscribers_range_min` | That range's lower end as a number (10000)                                                                                                                                                                                                                                                                                                               |
| `publication_bestseller_tier`            | The owner's Substack bestseller tier (100, 1000, 10000...), when they have one                                                                                                                                                                                                                                                                           |
| `publication_author_id`                  | The Substack id of the publication's owner                                                                                                                                                                                                                                                                                                               |
| `publication_owner_name`                 | The owner's name                                                                                                                                                                                                                                                                                                                                         |
| `publication_owner_handle`               | The owner's handle                                                                                                                                                                                                                                                                                                                                       |
| `publication_owner_bio`                  | The owner's bio                                                                                                                                                                                                                                                                                                                                          |
| `publication_owner_photo_url`            | The owner's photo                                                                                                                                                                                                                                                                                                                                        |
| `publication_twitter_screen_name`        | The publication's X (Twitter) name, when it has one                                                                                                                                                                                                                                                                                                      |
| `publication_cover_photo_url`            | The publication's cover photo, when it has one                                                                                                                                                                                                                                                                                                           |
| `publication_payments_state`             | Whether the publication takes paid subscriptions (`enabled`, `disabled`)                                                                                                                                                                                                                                                                                 |
| `publication_plans`                      | Its paid plans: name, `month` or `year`, the price (20 for $20) and currency, and whether it is on sale                                                                                                                                                                                                                                                  |
| `publication_founding_plan_name`         | The name of its top paid plan                                                                                                                                                                                                                                                                                                                            |
| `publication_free_benefits`              | What a free subscriber gets, as the writer lists it                                                                                                                                                                                                                                                                                                      |
| `publication_paid_benefits`              | What a paid subscriber gets                                                                                                                                                                                                                                                                                                                              |
| `publication_founding_benefits`          | What a founding member gets                                                                                                                                                                                                                                                                                                                              |
| `publication_paywall_free_trial_enabled` | `true` when the publication offers a free trial                                                                                                                                                                                                                                                                                                          |
| `publication_has_podcast`                | `true` when the publication has a podcast                                                                                                                                                                                                                                                                                                                |
| `publication_podcast_title`              | The podcast's title                                                                                                                                                                                                                                                                                                                                      |
| `publication_podcast_description`        | The podcast's description                                                                                                                                                                                                                                                                                                                                |
| `publication_podcast_byline`             | The podcast's byline                                                                                                                                                                                                                                                                                                                                     |
| `publication_podcast_feed_url`           | The podcast's own feed link, when it has one                                                                                                                                                                                                                                                                                                             |
| `publication_podcast_art_url`            | The podcast's artwork                                                                                                                                                                                                                                                                                                                                    |
| `publication_sections`                   | The publication's sections: id, name, slug, and whether it is a podcast                                                                                                                                                                                                                                                                                  |
| `publication_contributors`               | The people who write for it: id, name, handle, role, whether they own it, bio and photo                                                                                                                                                                                                                                                                  |
| `publication_has_recommendations`        | `true` when the publication recommends other publications                                                                                                                                                                                                                                                                                                |
| `publication_email_from_name`            | The sender name on the publication's emails                                                                                                                                                                                                                                                                                                              |
| `publication_copyright`                  | The publication's copyright line                                                                                                                                                                                                                                                                                                                         |
| `publication_homepage_type`              | The publication's home page layout                                                                                                                                                                                                                                                                                                                       |
| `publication_community_enabled`          | `true` when the publication has a community (chat) for readers                                                                                                                                                                                                                                                                                           |
| `publication_invite_only`                | `true` when the publication is invite only                                                                                                                                                                                                                                                                                                               |
| `publication_explicit`                   | `true` when the publication is marked explicit                                                                                                                                                                                                                                                                                                           |
| `body_read`                              | With body on: `true` when the post's body was read. Empty with body off                                                                                                                                                                                                                                                                                  |
| `comments_read`                          | With comments on: `true`, the post's comments were read (a post whose thread cannot be read is not saved). Empty with comments off                                                                                                                                                                                                                       |
| `comments`                               | With comments on: the post's whole comment thread, replies included, in reading order. Each comment has its id, the comment it answers (`parent_id`), its depth, text, dates, the commenter's id, name, handle and photo, whether they are the author, their membership, likes, restacks, reply count, score, status and whether it is pinned or deleted |
| `source_url`                             | The link you gave that this post was read from                                                                                                                                                                                                                                                                                                           |

Not included: the paid part of a paid post (the text gives the free preview),
comments on a paid post (Substack shows them to subscribers only), Substack
Notes, exact paid-subscriber numbers (Substack shows a range), and search
across all of Substack.

### How much does it cost?

No surcharges and no paid options; an item that fails is not charged.

You pay for what you get:

- **$1 per 1,000 posts** ($0.001 a post), with or without the text and the comments. Each post is charged once per run.
- No start fee, and nothing per publication.

So a publication's 400 posts cost $0.40. If you set a maximum cost for a run, the Actor stops when it reaches it and keeps every post saved so far.

### How long does a run take?

About 100 posts in 10 to 20 seconds, and three whole newsletters, 4,142
posts, in about three minutes. With the text and comments on, each post
takes longer: 200 posts in about four minutes.

### Good to know

- **Check your input first.** A link that is not a publication, profile or
  post link stops the run before anything is read, and the message names it.
- **One link that cannot be read does not stop the run.** A domain that is
  not a Substack, a post that was taken down or a writer with no publication
  ends with a message, the others carry on, and the run's status lists them.
  The run fails only when no link could be read.
- **Paid posts.** Their row has every field but the paid part of the text;
  `is_paid` marks them.
- **Large threads.** A post with hundreds of comments makes a large row; keep
  comments off when you only need the counts.
- **Counts move.** Likes, comments and restacks are the numbers at the moment
  the post was read.
- **Remove repeats by `post_id`.** A daily run reads recent posts again,
  unless **Only new posts** is on.

### More Actors from us

- [Airbnb Scraper: Every Stay, Past the 15-Page Limit](https://apify.com/luzivanlt/airbnb-listings-scraper): Every stay of an Airbnb search, past the 15 pages Airbnb shows, checked against its count.
- [Alibaba Products Scraper: Price Tiers & Suppliers](https://apify.com/luzivanlt/alibaba-products-scraper): Alibaba.com products by keyword or link, with price tiers in US dollars on every row.
- [AliExpress Product Scraper: Search Results & Prices](https://apify.com/luzivanlt/aliexpress-products-scraper): Every product of an AliExpress search to its last page, with exact sold counts and ratings.
- [Amazon Product Scraper: Search Results & Prices](https://apify.com/luzivanlt/amazon-products-scraper): Every product on Amazon's search pages to the last page, sponsored marked, with monthly sales.
- [App Store Reviews Scraper: All Reviews, Not 500](https://apify.com/luzivanlt/app-store-reviews-scraper): Every written App Store review of an app, not just the newest 500.
- [Woolworths Coles ALDI Scraper: AU Grocery Prices](https://apify.com/luzivanlt/au-supermarkets-scraper): Woolworths, Coles and ALDI products for any search in one run, every results page to the end.

### Use it from an AI agent or the API

One call starts a run and returns its items (Apify waits up to 300 seconds; for a
longer run, start it with `POST /v2/acts/…/runs` and read its dataset):

```text
POST https://api.apify.com/v2/acts/luzivanlt~substack-posts-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>
```

With the sample input as its JSON body:

```json
{
  "startUrls": ["https://www.lennysnewsletter.com", "https://noahpinion.substack.com"],
  "maxPostsPerPublication": 50,
  "includeBody": false,
  "includeComments": false
}
```

Its inputs, in the order of the input form:

| Input                                                | What it takes                                                                                                                                                                                                                                                                                     | Default |
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
| `startUrls` (Substack links)                         | Substack newsletters to read: a publication's link (https://example.substack.com, or its own domain such as https://www.example.com), any page of it, a writer's profile (https://substack.com/@handle or @handle) for their own publication, or a post's link (…/p/post-name) for that one post. | —       |
| `onlyPostsNewerThan` (Only posts newer than)         | Keep only posts published from this date on: a date (YYYY-MM-DD, UTC) or a period, e.g. "7 days", "2 weeks", "3 months" or "1 year".                                                                                                                                                              | —       |
| `maxPostsPerPublication` (Max posts per publication) | Stop reading a publication after this many posts, newest first, from 1 to 50,000.                                                                                                                                                                                                                 | `100`   |
| `includeBody` (Include post text)                    | Also read each post's full text, as HTML and as plain text, with its last update date and the posts before and after it.                                                                                                                                                                          | `false` |
| `includeComments` (Include comments)                 | Also read each post's whole comment thread, replies included, into the post's row: each comment's text, date, likes, the commenter's name and handle, and the comment it answers.                                                                                                                 | `false` |
| `onlyNewItems` (Only new posts)                      | Turn this on for a scheduled run, or a re-run of the same task: each run then returns only the posts it has not returned before, reading each publication back to a day before the last run that read it.                                                                                         | —       |

Apify's MCP server, `https://mcp.apify.com`, lists it as `luzivanlt/substack-posts-scraper`. To give an
AI agent this Actor as a tool, add the server to the agent's MCP config:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=luzivanlt/substack-posts-scraper"
    }
  }
}
```

The client signs in with OAuth, or add `"headers": { "Authorization": "Bearer <APIFY_TOKEN>" }`.

Charged per post delivered; the sample input above costs at most $0.10.

### FAQ

**Do I need a Substack account?**
No. The Actor reads what anyone can see on Substack without signing in.

**Does it work with a newsletter on its own domain?**
Yes. Paste the domain, such as `https://www.lennysnewsletter.com`, or the
newsletter's `substack.com` address.

**Can I run it from my own code, on a schedule, or with other apps?**
Yes. Like any Apify Actor, you can start it through the Apify API, run it on a
schedule, and connect it to other apps with Apify's integrations and webhooks.

### Is it legal to scrape Substack?

This Actor reads only public posts and comments. Authors' and commenters'
names, handles and photos are personal data; treat them as such. Check
Substack's terms and the laws that apply to you (such as the GDPR or the
CCPA) before you use the data. If you are unsure, ask a lawyer.

### Support

Found a problem or missing a feature? Open an issue on the **Issues** tab and
include the run's link.

***

This Actor is not affiliated with, endorsed by or sponsored by Substack.

# Changelog

This Actor's version history is a separate document: https://apify.com/luzivanlt/substack-posts-scraper/changelog.md

# Actor input Schema

## `startUrls` (type: `array`):

Substack newsletters to read: a publication's link (https://example.substack.com, or its own domain such as https://www.example.com), any page of it, a writer's profile (https://substack.com/@handle or @handle) for their own publication, or a post's link (…/p/post-name) for that one post. A bare name (example) means example.substack.com. Example: https://www.lennysnewsletter.com

## `onlyPostsNewerThan` (type: `string`):

Keep only posts published from this date on: a date (YYYY-MM-DD, UTC) or a period, e.g. "7 days", "2 weeks", "3 months" or "1 year". The date cannot be in the future. Applies to every publication and profile (a post link always gives its post); older posts are not saved or charged. Leave empty for the whole archive.

## `maxPostsPerPublication` (type: `integer`):

Stop reading a publication after this many posts, newest first, from 1 to 50,000. The form starts at 50; left empty, it is 100. Each post is charged once ($1 per 1,000 posts), so this caps what one publication costs: 1,000 posts cost at most $1.

## `includeBody` (type: `boolean`):

Also read each post's full text, as HTML and as plain text, with its last update date and the posts before and after it. A paid post gives its free preview only. Takes one more request per post, so runs are slower; the price per post stays the same.

## `includeComments` (type: `boolean`):

Also read each post's whole comment thread, replies included, into the post's row: each comment's text, date, likes, the commenter's name and handle, and the comment it answers. Substack shows a paid post's comments only to subscribers, so those come back empty. One more request per post; the price per post stays the same.

## `onlyNewItems` (type: `boolean`):

Turn this on for a scheduled run, or a re-run of the same task: each run then returns only the posts it has not returned before, reading each publication back to a day before the last run that read it. Skipped posts are neither saved nor charged; each new post is charged as usual. Runs with other settings, or from another task, keep their own list. Off by default.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.lennysnewsletter.com",
    "https://noahpinion.substack.com"
  ],
  "maxPostsPerPublication": 50,
  "includeBody": false,
  "includeComments": false
}
```

# Actor output Schema

## `posts` (type: `string`):

Every post the run saved, one row per post.

## `allFields` (type: `string`):

The same rows with every field.

## `runReport` (type: `string`):

What happened to each input: items saved, nothing found, refused by the site, stopped at your limit, or the error.

# 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 = {
    "startUrls": [
        "https://www.lennysnewsletter.com",
        "https://noahpinion.substack.com"
    ],
    "maxPostsPerPublication": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("luzivanlt/substack-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 = {
    "startUrls": [
        "https://www.lennysnewsletter.com",
        "https://noahpinion.substack.com",
    ],
    "maxPostsPerPublication": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("luzivanlt/substack-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 '{
  "startUrls": [
    "https://www.lennysnewsletter.com",
    "https://noahpinion.substack.com"
  ],
  "maxPostsPerPublication": 50
}' |
apify call luzivanlt/substack-posts-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,luzivanlt/substack-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/xfMAd8AHGYrLygCO6/builds/jVdpjnuC9IBbm7mSs/openapi.json
