# Substack Scraper - Newsletters, Subscribers, Posts (`om_kh/substack-scraper`) Actor

Scrape Substack newsletters and posts: subscribers, paid prices, author socials, posts with likes, restacks, full text or HTML and comments. Search posts by topic across Substack, find top newsletters by category, filter by date and type. No login. From $0.50 per 1,000 posts.

- **URL**: https://apify.com/om_kh/substack-scraper.md
- **Developed by:** [Khandji Omar](https://apify.com/om_kh) (community)
- **Categories:** Social media, Lead generation, News
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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 Scraper — Newsletters, Subscribers, Posts

> Scrape **Substack newsletters and their posts**: **subscriber count**, paid prices, author
> followers and social links, plus every post with **likes, comments, restacks**, word count,
> free or paid, and optionally the **full text, the HTML and the comments**. **Search posts by
> topic across all of Substack** and **discover the top newsletters of any
> category** (Technology, Business, Finance…). No login. **$0.50 per 1,000 posts, no start fee.**

### Free tier — 20 results free on every run

**The first 20 results of every run are free**, on every run you ever make — not a one-off trial. One guard: the free allowance never covers more than half of a run, so the offer stays sustainable.

### What does this Substack scraper do?

Give it newsletters (a link to any page, a custom domain, `name.substack.com` or just `lenny`)
and/or **categories**. For each newsletter you get one row with its card — subscribers, paid
plans, author, followers, socials — followed by its posts, newest first, back to the date you
choose.

### Compared with automation-lab/substack-scraper

Read on the Store on 2026-10-23 (Substack Scraper). Where it does better, this section says so.

- **Built on the site's own data**, not a resold scraper: no second Actor between you and the source.
- **Free results on every run** and a hard cost cap (`maxTotalChargeUsd`).
- **Price:** $2 per 1,000 here, $1.15 there.

### Why use it

1. **Subscriber counts and prices** on every newsletter — ready for sponsorship and
   partnership prospecting.
2. **Category discovery:** the top 25 to 1,000 newsletters of a category, ranked, with their
   numbers. Find the right newsletters to sponsor in minutes.
3. **Engagement per post:** likes, comments, restacks and word count, free or paid.
4. **Full text of free posts** for AI, RAG, summaries and research (paid posts: public preview,
   charged as a plain post).
5. **Cheaper than the market leader** and no start fee.
6. **API, n8n, Make, Zapier and MCP ready.**

### How to use it in 3 steps

1. Click **Try for free** — a newsletter and a category are prefilled.
2. Add newsletters or categories; choose how many posts and whether you want the text.
3. Click **Start** and download JSON, CSV or Excel.

### Input

| Field | What it does |
|---|---|
| `newsletters` | Links, custom domains, `name.substack.com` or subdomains. |
| `categories` | Leaderboard categories: Technology, Business, Finance, Culture, Politics, Science, Crypto, Health & Wellness, Food & Drink, Sports… |
| `maxNewslettersPerCategory` | Top-ranked first, 1 to 1,000. Default 25. |
| `paidOnly` | Use the paid leaderboard (ranked by paid subscribers). |
| `maxPostsPerNewsletter` | 0 to 5,000, newest first. 0 = newsletter info only. Default 20. |
| `includeText` | Full text of free posts (preview of paid posts). |
| `postedAfter` | Optional `YYYY-MM-DD`: only posts on or after it. |
| `postedBefore` | Optional `YYYY-MM-DD`: only posts on or before it. |
| `keywords` | Topics to search across all of Substack (up to 50). |
| `maxPostsPerKeyword` | Posts per topic, 1 to 500. Default 20. |
| `contentType` | `all` (default), `newsletter`, `podcast` or `thread`. |
| `onlyFree` | Skip paywalled posts. |
| `includeHtml` | Add the full HTML body next to the plain text. |
| `includeComments` / `maxCommentsPerPost` | Add each post's comments and replies in `commentsList` (up to 2,000 per post). No extra charge. |
| `maxTotalChargeUsd` | Optional hard cost cap for the run. |

```json
{
  "categories": ["Technology", "Business"],
  "maxNewslettersPerCategory": 100,
  "maxPostsPerNewsletter": 0
}
```

### Output

Real examples. A newsletter row:

```json
{
  "type": "newsletter",
  "name": "Lenny's Newsletter",
  "url": "https://www.lennysnewsletter.com",
  "subscribers": 1200000,
  "subscribersText": "1.2M+",
  "leaderboardBadge": "Tens of thousands of paid subscribers",
  "paidEnabled": true,
  "monthlyPriceUsd": 20.0,
  "yearlyPriceUsd": 200.0,
  "hasPodcast": true,
  "firstPostDate": "2019-06-14T15:00:48.833Z",
  "authorName": "Lenny Rachitsky",
  "authorFollowers": 1381643,
  "authorSocials": {
    "twitter": "https://x.com/lennysan",
    "youtube": "https://www.youtube.com/c/LennysPodcast"
  },
  "authorWebsite": "https://www.lennyrachitsky.com/",
  "profileUrl": "https://substack.com/@lenny"
}
```

A post row:

```json
{
  "type": "post",
  "newsletterUrl": "https://www.lennysnewsletter.com",
  "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",
  "audience": "free",
  "likes": 263,
  "comments": 5,
  "restacks": 4,
  "wordCount": 1276,
  "authors": ["Lenny Rachitsky"]
}
```

With `includeText`, posts also carry `text` and `textIsFull`.

### How much does it cost?

| Event | Price |
|---|---|
| Newsletter (card with subscribers, prices, author, socials) | **$0.002** |
| Post (title, date, likes, comments, restacks…) | **$0.0005** ($0.50 per 1,000) |
| Post with full text (free posts) | **$0.001** |
| Start fee | none |

Up to 20 results of every run are free (at most half of the run). Newsletters that do not
exist are reported and never charged. Paid Apify plans get lower tier prices.

### Use cases

- **Newsletter sponsorship** — the biggest newsletters of a niche, with subscribers and prices.
- **Creator and influencer outreach** — authors with followers and social links.
- **Content research** — what performs (likes, comments, restacks) in a niche.
- **AI and RAG** — clean full text of free posts with dates and authors.
- **Monitoring** — new posts of a list of newsletters with a daily schedule and `postedAfter`.

### Use it from code (API)

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("om_kh/substack-scraper").call(run_input={
    "categories": ["Finance"],
    "maxNewslettersPerCategory": 50,
    "maxPostsPerNewsletter": 0,
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row["name"], row.get("subscribers"), row.get("monthlyPriceUsd"))
```

```bash
curl -X POST "https://api.apify.com/v2/acts/om_kh~substack-scraper/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"newsletters": ["lenny"], "maxPostsPerNewsletter": 10}'
```

### Integrations and MCP

Schedule it daily with `postedAfter` and send new posts to Slack, Notion or Google Sheets with
n8n, Make or Zapier. AI agents can call it through `https://mcp.apify.com` as
`om_kh/substack-scraper`.

### Tips and limits

- Subscriber counts are the ones Substack shows publicly (exact for most, rounded like
  "1.2M+" for the largest).
- `contactEmail` is filled only when the newsletter publishes a support email.
- Comments' text and paid post bodies need a subscription and are not offered.

### FAQ

**Do I need a Substack account?** No.

**Is it legal?** It reads what newsletters publish publicly. Use the data in line with the
laws and terms that apply to you.

### Related Actors

- [YouTube Channel Email Scraper - Business Emails, Socials](https://apify.com/om_kh/youtube-channel-email-scraper) — creators on YouTube.
- [Google News Scraper - Headlines, Source, Date, API](https://apify.com/om_kh/google-news-scraper) — news coverage of the same topics.
- [Hacker News Scraper - Posts, Points, Comment Count](https://apify.com/om_kh/hacker-news-scraper) — where tech newsletters get discussed.

### Your feedback

Did this Actor save you time? A short review on the **Reviews** tab helps other people find it, and every review is read. Something missing or broken? Open an issue on the **Issues** tab: it is answered and fixed fast.

# Actor input Schema

## `newsletters` (type: `array`):

Substack newsletters: links (any page of the newsletter, custom domains work), name.substack.com, or just the subdomain (e.g. lenny).

## `categories` (type: `array`):

Substack leaderboard categories to discover top newsletters, e.g. Technology, Business, Finance, Culture, Politics, Health & Wellness, Food & Drink, Sports, Science, Crypto.

## `maxNewslettersPerCategory` (type: `integer`):

Top-ranked first, 1 to 1,000. Default 25.

## `paidOnly` (type: `boolean`):

Use the leaderboard of paid newsletters (ranked by paid subscribers).

## `keywords` (type: `array`):

Find public posts across all of Substack for these topics, e.g. artificial intelligence, climate policy (up to 50).

## `maxPostsPerKeyword` (type: `integer`):

1 to 500. Default 20.

## `maxPostsPerNewsletter` (type: `integer`):

Newest first, 0 to 5,000. 0 = newsletter info only. Default 20.

## `includeText` (type: `boolean`):

Full text of free posts (and the public preview of paid posts). One extra request per post.

## `includeHtml` (type: `boolean`):

Add the full HTML body next to the plain text (same price as the text).

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

Add each post's comments and replies in a commentsList field. No extra charge.

## `maxCommentsPerPost` (type: `integer`):

1 to 2,000, replies included. Default 20.

## `postedAfter` (type: `string`):

Only posts on or after this date (YYYY-MM-DD).

## `postedBefore` (type: `string`):

YYYY-MM-DD. Keep only posts published on or before this day.

## `contentType` (type: `string`):

Keep only this kind of post.

## `onlyFree` (type: `boolean`):

Skip paywalled posts.

## `maxTotalChargeUsd` (type: `number`):

Optional hard cost cap for this run.

## Actor input object example

```json
{
  "newsletters": [
    "lenny"
  ],
  "categories": [
    "Technology"
  ],
  "maxNewslettersPerCategory": 10,
  "paidOnly": false,
  "maxPostsPerKeyword": 20,
  "maxPostsPerNewsletter": 5,
  "includeText": false,
  "includeHtml": false,
  "includeComments": false,
  "maxCommentsPerPost": 20,
  "contentType": "all",
  "onlyFree": false
}
```

# Actor output Schema

## `report` (type: `string`):

A visual summary of delivery, charges, and source issues.

## `results` (type: `string`):

Newsletters and posts in a sortable table. No JSON knowledge required.

## `csv` (type: `string`):

Results ready for spreadsheets, CRMs, and analytics tools.

## `excel` (type: `string`):

Results as an Excel workbook for non-technical teams.

## `runSummary` (type: `string`):

Machine-readable delivery, billing, and source diagnostics.

# 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 = {
    "newsletters": [
        "lenny"
    ],
    "categories": [
        "Technology"
    ],
    "maxNewslettersPerCategory": 10,
    "maxPostsPerNewsletter": 5
};

// Run the Actor and wait for it to finish
const run = await client.actor("om_kh/substack-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 = {
    "newsletters": ["lenny"],
    "categories": ["Technology"],
    "maxNewslettersPerCategory": 10,
    "maxPostsPerNewsletter": 5,
}

# Run the Actor and wait for it to finish
run = client.actor("om_kh/substack-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 '{
  "newsletters": [
    "lenny"
  ],
  "categories": [
    "Technology"
  ],
  "maxNewslettersPerCategory": 10,
  "maxPostsPerNewsletter": 5
}' |
apify call om_kh/substack-scraper --silent --output-dataset

```

## MCP server setup

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