# Substack Scraper — Posts·Comments·Subscribers w/ EMAILS (`memo23/substack-scraper`) Actor

Scrape Substack newsletters — full post content, threaded comments, tags, authors, podcast episodes and EXACT subscriber counts. Works with custom domains, date filters, paid-post detection, optional author contact emails. Any publication or post URL. Pure HTTP, JSON/CSV out.

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

## Pricing

from $3.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## Substack Scraper — Posts, Comments & Subscriber Counts

Scrape any Substack newsletter into clean, structured data — full post content, threaded comments, tags, authors, podcast episodes and **exact free-subscriber counts**. Works with `*.substack.com` subdomains **and** custom domains, follows publication moves automatically, and detects paywalled posts honestly. Pure HTTP against Substack's public JSON API — no browser, fast and cheap.

#### How it works

<p align="center"><img src="https://api.apify.com/v2/key-value-stores/4tlKsg4LpkW4YuoVT/records/how-it-works-substack.png" width="900" alt="How the Substack scraper works"></p>

#### ✨ Why use this scraper?

- **Any URL shape** — newsletter homepages, custom domains (`www.noahpinion.blog`), `/archive`, `/about`, or direct post URLs (`/p/{slug}`). Bare names work too (`"noahpinion"`).
- **Full post content** — `bodyHtml` + clean `bodyText`, word counts, cover images, tags, authors with bios, podcast audio URLs and durations.
- **Threaded comments** — one row per comment with `parentCommentId` + `depth` preserved, joinable to posts via `postId`.
- **Exact subscriber counts** — the publication row carries the precise `freeSubscriberCount` (e.g. `454000`), not just "454K+".
- **Honest paywall handling** — paid posts return their free preview flagged `bodyIsPreviewOnly: true`; filter them out entirely with `onlyFree`.
- **Date-window scraping** — `startDate` + newest-first sort stops paginating at the cutoff, so monitoring runs stay small and cheap.

#### 🎯 Use cases

| Audience | What they pull |
|---|---|
| Newsletter analysts & investors | Subscriber counts, posting cadence, engagement (reactions/comments) across a portfolio of publications |
| Content & SEO teams | Full archives as clean text for topic research, repurposing, or LLM fine-tuning corpora |
| Community managers | Comment threads with authors and reply structure for sentiment and superfan analysis |
| Podcast researchers | Episode metadata + audio URLs from podcast-type posts |
| Lead generation | Publication rows with author names, handles and opt-in contact-email enrichment |
| Media monitors | Daily `startDate`-windowed runs over a watchlist of newsletters |

#### 📥 Supported inputs

| Input | Example | What it does |
|---|---|---|
| Newsletter homepage | `https://noahpinion.substack.com` | Walks the archive, newest first |
| Custom domain | `https://www.noahpinion.blog` | Same — custom domains serve the same API |
| Archive / About page | `https://thezvi.substack.com/archive` | Treated as the publication root |
| Direct post URL | `https://…/p/some-post-slug` | Scrapes just that post |
| Bare name (`publications` field) | `noahpinion` | Expands to the subdomain homepage |

Not supported: Substack Notes, Chat, private/logged-in-only publications, and full text of paywalled posts (previews only — see FAQ).

#### 🔄 How it works

1. **Classify** each start URL — publication root vs direct post.
2. **Resolve moves** — `{name}.substack.com` publications that migrated to a custom domain are followed automatically (e.g. Astral Codex Ten).
3. **Walk the archive API** page by page, applying your filters; with `startDate` + newest-first sort it stops at the cutoff.
4. **Fetch full content** per post (the archive API only carries metadata), plus **comments** and the **publication info** row when enabled.
5. **Push rows** — `post`, `comment`, and `publication` row types, joinable via `postId` / `publicationUrl`.

#### ⚙️ Input parameters

| Field | Type | Default | Description |
|---|---|---|---|
| `startUrls` | array | — | Substack URLs (homepage, custom domain, /archive, /about, /p/… post) |
| `publications` | array | — | Bare subdomains/domains, each expands to a homepage |
| `maxPostsPerNewsletter` | integer | `50` | Posts per newsletter; `0` = full archive |
| `maxItems` | integer | `1000` | Hard cap on post rows for the whole run |
| `sortOrder` | string | `new` | `new` (newest first) or `top` (most popular) |
| `includeBody` | boolean | `true` | Full `bodyHtml` + `bodyText` (one extra API call per post) |
| `includeComments` | boolean | `false` | Emit `comment` rows per post |
| `maxCommentsPerPost` | integer | `100` | Comment rows per post incl. replies; `0` = unlimited |
| `includePublicationInfo` | boolean | `true` | One `publication` row per newsletter |
| `contentType` | string | `all` | `all` / `newsletter` / `podcast` / `thread` |
| `startDate` / `endDate` | string | — | `YYYY-MM-DD` publish-date window |
| `onlyFree` | boolean | `false` | Skip paywalled posts entirely |
| `enrichEmails` | boolean | `false` | Opt-in author/publication contact-email discovery (billed per email found) |
| `maxConcurrency` | integer | `5` | Posts processed in parallel |
| `proxy` | object | built-in | Explicit override only; leave empty for the built-in residential routing |

Example input:

```json
{
    "startUrls": ["https://www.noahpinion.blog", "https://astralcodexten.substack.com"],
    "maxPostsPerNewsletter": 50,
    "includeComments": true,
    "maxCommentsPerPost": 100,
    "includePublicationInfo": true,
    "startDate": "2026-01-01",
    "sortOrder": "new"
}
````

#### 📊 Output overview

The dataset mixes three row types, distinguished by `rowType`:

| `rowType` | One row per | Join keys |
|---|---|---|
| `post` | post (newsletter / podcast / thread) | `postId`, `publicationUrl` |
| `comment` | comment, replies flattened with `parentCommentId` + `depth` | `postId`, `postSlug` |
| `publication` | newsletter (when `includePublicationInfo`) | `publicationId`, `baseUrl` |

#### 📦 Output samples

`post` row (trimmed, real run):

```json
{
    "rowType": "post",
    "postId": 207376523,
    "slug": "book-review-power-and-progress-874",
    "url": "https://www.noahpinion.blog/p/book-review-power-and-progress-874",
    "title": "Book Review: \"Power and Progress\"",
    "contentType": "newsletter",
    "audience": "everyone",
    "isPaid": false,
    "bodyIsPreviewOnly": false,
    "postDate": "2026-07-16T12:01:32.192Z",
    "bodyHtml": "<p>…full HTML…</p>",
    "bodyText": "Daron Acemoglu…",
    "wordCount": 7414,
    "coverImage": "https://substack-post-media.s3.amazonaws.com/public/images/…",
    "tags": [],
    "authors": [{ "id": 8243895, "name": "Noah Smith", "handle": "noahpinion", "bio": "Econ blogger", "twitter": "Noahpinion" }],
    "reactionCount": 208,
    "commentCount": 89,
    "restacks": 14,
    "publicationUrl": "https://www.noahpinion.blog",
    "scrapedAt": "2026-07-19T21:03:44.118Z"
}
```

`comment` row:

```json
{
    "rowType": "comment",
    "commentId": 296191763,
    "postId": 207376523,
    "postSlug": "book-review-power-and-progress-874",
    "parentCommentId": null,
    "depth": 0,
    "authorName": "Russ S. Chien",
    "authorHandle": "chieninsights",
    "date": "2026-07-17T04:54:30.484Z",
    "bodyText": "I haven't read this book Power and Progress, but I couldn't agree more…",
    "reactionCount": 10,
    "repliesCount": 2,
    "publicationUrl": "https://www.noahpinion.blog"
}
```

`publication` row:

```json
{
    "rowType": "publication",
    "publicationId": 35345,
    "name": "Noahpinion",
    "subdomain": "noahpinion",
    "customDomain": "www.noahpinion.blog",
    "baseUrl": "https://www.noahpinion.blog",
    "authorName": "Noah Smith",
    "authorHandle": "noahpinion",
    "freeSubscriberCount": 454000,
    "subscriberCountText": "454K+",
    "language": "en",
    "createdAt": "2020-09-25T21:19:04.505Z"
}
```

#### 🗂 Key output fields

**Post identity & content:** `postId`, `slug`, `url`, `title`, `subtitle`, `description`, `bodyHtml`, `bodyText`, `wordCount`, `coverImage`, `tags[]`
**Engagement:** `reactionCount`, `commentCount`, `childCommentCount`, `restacks`
**Monetisation signals:** `audience` (`everyone` / `only_paid` / `founding`), `isPaid`, `bodyIsPreviewOnly`
**Podcast:** `contentType: "podcast"`, `podcastUrl`, `podcastDurationSec`
**People:** `authors[]` (id, name, handle, photo, bio, twitter), comment `authorName` / `authorHandle`
**Publication:** `freeSubscriberCount` (exact), `subscriberCountText`, `customDomain`, `authorBio`, `createdAt`, `copyright`
**Enrichment (opt-in):** `contactEmail`, `contactWebsite`, `emailEnrichment` on the publication row

#### ❓ FAQ

**Q: Can it scrape paywalled posts?**
No — paywalled posts return only the free preview Substack itself exposes, flagged `bodyIsPreviewOnly: true` (some return no body at all). We don't bypass the paywall or accept Substack accounts. Use `onlyFree: true` to skip them entirely.

**Q: How do I scrape a full archive?**
Set `maxPostsPerNewsletter: 0` and raise `maxItems`. Archives paginate 20 posts per API call.

**Q: Does it work for newsletters on their own domains?**
Yes — custom domains serve the same API. Publications that moved from `{name}.substack.com` to a custom domain are followed automatically.

**Q: Where does the subscriber count come from?**
The publication's own About page metadata — the exact free-subscriber figure (`454000`), plus the display string (`454K+`). A handful of publications hide it; then both fields are `null`.

**Q: How are comment replies represented?**
Flattened — every comment is its own row with `parentCommentId` and `depth`, so you can rebuild the tree or just count engagement.

**Q: What does email enrichment do?**
Opt-in: it discovers the author/publication's own website and reads its public contact pages. You're billed per email actually found, never for misses.

**Q: Substack Notes / Chat?**
Not covered — this actor is posts, comments, and publication metadata.

#### 💬 Support

Found an issue or need a field added? Open an issue on the actor's **Issues** tab — response time is typically under a day.

#### 🛠 Additional services

Need a custom pipeline (scheduled monitoring, delivery to Sheets/BigQuery, cross-newsletter dashboards) or a scraper for another site? Contact us via the Issues tab or muhamed.didovic@gmail.com.

#### 🔎 Explore more scrapers

- [G2 Reviews + AI Intelligence](https://apify.com/memo23/g2-scraper)
- [Trustpilot Scraper](https://apify.com/memo23/trustpilot-scraper)
- [Gumroad Scraper — Products, Sellers & Creator Email](https://apify.com/memo23/gumroad-scraper)
- [Naver Blog Scraper](https://apify.com/memo23/naver-blog-scraper)

***

### ⚠️ Disclaimer

This Actor is an independent tool and is not affiliated with, endorsed by, or sponsored by Substack Inc. or any of its subsidiaries or affiliates. All trademarks mentioned are the property of their respective owners.

The scraper accesses only publicly available pages and public API endpoints — no authenticated endpoints, no paywall bypass, and no content behind a Substack login. Paywalled posts yield only the public preview Substack itself serves to anonymous visitors. Users are responsible for ensuring their use complies with Substack's Terms of Service, applicable data-protection law (GDPR, CCPA, etc.), and any contractual obligations of their own organisation.

***

### SEO Keywords

substack scraper, scrape substack, substack api, substack newsletter scraper, substack posts scraper, substack comments scraper, substack subscriber count, newsletter scraper, newsletter data extraction, substack archive export, substack to csv, substack to json, newsletter market research, creator economy data, substack podcast scraper, newsletter monitoring, substack analytics, apify substack, substack rss alternative, author contact email finder

# Actor input Schema

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

Substack URLs to scrape. Newsletter homepages (https://noahpinion.substack.com or custom domains like https://www.noahpinion.blog), /archive or /about pages, and direct post URLs (https://…/p/some-post) are auto-classified.

## `publications` (type: `array`):

Bare Substack subdomains or domains — each expands to that publication's homepage. E.g. 'noahpinion' expands to https://noahpinion.substack.com. Used in addition to Start URLs.

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

Maximum number of posts to scrape per newsletter. Set to 0 for unlimited (full archive).

## `maxItems` (type: `integer`):

Hard cap on post rows across the whole run (all newsletters combined).

## `sortOrder` (type: `string`):

Archive ordering. 'new' = newest first (recommended — enables early stop when combined with Start date). 'top' = most popular first.

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

Include the full post body as HTML and plain text. Disable for metadata-only scraping — smaller rows, faster runs. Note: paywalled posts return only their free preview portion (flagged via bodyIsPreviewOnly).

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

Fetch comments for each post (one extra API call per post that has comments). Emits one rowType:'comment' row per comment with parentCommentId preserved, joinable to posts via postId.

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

Maximum comment rows per post, including nested replies. Set to 0 for unlimited. Only applies when 'Include comments' is on.

## `includePublicationInfo` (type: `boolean`):

Emit one rowType:'publication' row per newsletter — name, author (name/handle/bio), description, EXACT free-subscriber count, custom domain, language, created date.

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

Filter by post type.

## `startDate` (type: `string`):

Only posts published on or after this date. With sort order 'Newest first' the scraper stops paginating at the cutoff — fewer API calls, faster and cheaper.

## `endDate` (type: `string`):

Only posts published on or before this date.

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

Skip paywalled posts (audience is 'only\_paid' or 'founding'). Paywalled posts otherwise return their free preview portion.

## `enrichEmails` (type: `boolean`):

Try to find a contact email for each publication/author by discovering their website and reading its contact/about pages. Adds contactEmail + contactWebsite to the publication row plus a detailed emailEnrichment object. Billed per email found — never charged for misses.

## `maxConcurrency` (type: `integer`):

How many posts to process in parallel. Substack's API tolerates moderate parallelism; raise carefully (429s are auto-retried with back-off).

## `maxRequestRetries` (type: `integer`):

Retries for failed API requests.

## `proxy` (type: `object`):

Explicit proxy override. Leave empty to use the actor's built-in residential routing (recommended).

## Actor input object example

```json
{
  "startUrls": [
    "https://www.noahpinion.blog",
    "https://thezvi.substack.com"
  ],
  "maxPostsPerNewsletter": 50,
  "maxItems": 1000,
  "sortOrder": "new",
  "includeBody": true,
  "includeComments": false,
  "maxCommentsPerPost": 100,
  "includePublicationInfo": true,
  "contentType": "all",
  "onlyFree": false,
  "enrichEmails": false,
  "maxConcurrency": 5,
  "maxRequestRetries": 5
}
```

# 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.noahpinion.blog",
        "https://thezvi.substack.com"
    ]
};

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

# Run the Actor and wait for it to finish
run = client.actor("memo23/substack-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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.noahpinion.blog",
    "https://thezvi.substack.com"
  ]
}' |
apify call memo23/substack-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=memo23/substack-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Substack Scraper — Posts·Comments·Subscribers w/ EMAILS",
        "description": "Scrape Substack newsletters — full post content, threaded comments, tags, authors, podcast episodes and EXACT subscriber counts. Works with custom domains, date filters, paid-post detection, optional author contact emails. Any publication or post URL. Pure HTTP, JSON/CSV out.",
        "version": "0.0",
        "x-build-id": "2IbJV9lMHcRrKlCbb"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/memo23~substack-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-memo23-substack-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/memo23~substack-scraper/runs": {
            "post": {
                "operationId": "runs-sync-memo23-substack-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/memo23~substack-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-memo23-substack-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "startUrls": {
                        "title": "Substack URLs",
                        "type": "array",
                        "description": "Substack URLs to scrape. Newsletter homepages (https://noahpinion.substack.com or custom domains like https://www.noahpinion.blog), /archive or /about pages, and direct post URLs (https://…/p/some-post) are auto-classified.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "publications": {
                        "title": "Publication shortcuts",
                        "type": "array",
                        "description": "Bare Substack subdomains or domains — each expands to that publication's homepage. E.g. 'noahpinion' expands to https://noahpinion.substack.com. Used in addition to Start URLs.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxPostsPerNewsletter": {
                        "title": "Max posts per newsletter",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Maximum number of posts to scrape per newsletter. Set to 0 for unlimited (full archive).",
                        "default": 50
                    },
                    "maxItems": {
                        "title": "Max posts total",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Hard cap on post rows across the whole run (all newsletters combined).",
                        "default": 1000
                    },
                    "sortOrder": {
                        "title": "Sort order",
                        "enum": [
                            "new",
                            "top"
                        ],
                        "type": "string",
                        "description": "Archive ordering. 'new' = newest first (recommended — enables early stop when combined with Start date). 'top' = most popular first.",
                        "default": "new"
                    },
                    "includeBody": {
                        "title": "Include post content (bodyHtml + bodyText)",
                        "type": "boolean",
                        "description": "Include the full post body as HTML and plain text. Disable for metadata-only scraping — smaller rows, faster runs. Note: paywalled posts return only their free preview portion (flagged via bodyIsPreviewOnly).",
                        "default": true
                    },
                    "includeComments": {
                        "title": "Include comments",
                        "type": "boolean",
                        "description": "Fetch comments for each post (one extra API call per post that has comments). Emits one rowType:'comment' row per comment with parentCommentId preserved, joinable to posts via postId.",
                        "default": false
                    },
                    "maxCommentsPerPost": {
                        "title": "Max comments per post",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Maximum comment rows per post, including nested replies. Set to 0 for unlimited. Only applies when 'Include comments' is on.",
                        "default": 100
                    },
                    "includePublicationInfo": {
                        "title": "Include publication info",
                        "type": "boolean",
                        "description": "Emit one rowType:'publication' row per newsletter — name, author (name/handle/bio), description, EXACT free-subscriber count, custom domain, language, created date.",
                        "default": true
                    },
                    "contentType": {
                        "title": "Content type",
                        "enum": [
                            "all",
                            "newsletter",
                            "podcast",
                            "thread"
                        ],
                        "type": "string",
                        "description": "Filter by post type.",
                        "default": "all"
                    },
                    "startDate": {
                        "title": "Start date (YYYY-MM-DD)",
                        "type": "string",
                        "description": "Only posts published on or after this date. With sort order 'Newest first' the scraper stops paginating at the cutoff — fewer API calls, faster and cheaper."
                    },
                    "endDate": {
                        "title": "End date (YYYY-MM-DD)",
                        "type": "string",
                        "description": "Only posts published on or before this date."
                    },
                    "onlyFree": {
                        "title": "Free posts only",
                        "type": "boolean",
                        "description": "Skip paywalled posts (audience is 'only_paid' or 'founding'). Paywalled posts otherwise return their free preview portion.",
                        "default": false
                    },
                    "enrichEmails": {
                        "title": "Enrich with contact emails (experimental, billed per email)",
                        "type": "boolean",
                        "description": "Try to find a contact email for each publication/author by discovering their website and reading its contact/about pages. Adds contactEmail + contactWebsite to the publication row plus a detailed emailEnrichment object. Billed per email found — never charged for misses.",
                        "default": false
                    },
                    "maxConcurrency": {
                        "title": "Max concurrency",
                        "minimum": 1,
                        "type": "integer",
                        "description": "How many posts to process in parallel. Substack's API tolerates moderate parallelism; raise carefully (429s are auto-retried with back-off).",
                        "default": 5
                    },
                    "maxRequestRetries": {
                        "title": "Max request retries",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Retries for failed API requests.",
                        "default": 5
                    },
                    "proxy": {
                        "title": "Proxy configuration (override)",
                        "type": "object",
                        "description": "Explicit proxy override. Leave empty to use the actor's built-in residential routing (recommended)."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
