Substack Scraper
Pricing
from $0.98 / 1,000 post rows
Substack Scraper
Scrape Substack publications and posts: subscriber count, paid plan prices, author, and every post with date, paid flag, likes, comments, restacks, authors, and tags. Search Substack by keyword for posts or the newsletters behind them. Public data, no login. Clay ready.
Pricing
from $0.98 / 1,000 post rows
Rating
0.0
(0)
Developer
Mamba Labs
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
10 hours ago
Last modified
Categories
Share
Scrape Substack publications and posts, or search all of Substack by keyword. For each publication you get its name, author, subscriber count as Substack shows it, paid plan prices, and its newest posts. Each post row carries the date, the paid or free flag, likes, comments, restacks, word count, bylines, and tags. A search returns the matching posts, or one row per newsletter behind them, which turns a topic into a list of newsletters to pitch, sponsor, or study. Rows are flat, so they export to CSV or drop into a Clay table.
Features
- Publication profile. Name, author, tagline, language, first post date, the subscriber count Substack prints on the homepage (Over 1,200,000 subscribers) or its rounded figure (1.3K+), Substack's subscriber tier text, and the monthly, yearly, and founding plan prices.
- Every post as a row. Title, subtitle, URL, publish time,
audience(free, paid, or founding), word count, likes, comments, restacks, bylines with guest writers, and tags. Optional post text, where a paid post gives its free preview. - Search Substack. Keyword search across Substack posts, with each post's publication and subscriber count on the same row. Set Search output to publications for one row per newsletter instead.
- Any address works. Custom domains (lennysnewsletter.com), substack.com subdomains, profile links (substack.com/@lenny), or a bare name (lenny).
- Date window. Keep only posts from the last N days.
How it reads Substack
Substack's public pages and the public JSON routes its own site uses: the publication homepage, the post archive, and post search. robots.txt is read for every host and checked before every request. No login, no account, no API key, and no other developer's actor. A host that refuses a direct request is retried through the Apify proxy.
Input
| Field | Type | Default | What it does |
|---|---|---|---|
publications | array | Up to 100 publications: a URL, a domain, a substack.com profile, or a bare Substack name | |
search_queries | array | Up to 20 keyword searches across Substack posts | |
search_output | string | posts | posts for one row per matching post, publications for one row per newsletter behind them |
max_posts_per_publication | string | 20 | Newest posts per publication, 0 to 1000. 0 returns only the publication row |
max_search_results | string | 50 | Rows per search query, 1 to 1000 |
since_days | string | 0 | Skip posts older than this many days. 0 keeps all |
include_publication_row | string | true | false returns post rows only |
include_body | string | false | true adds the post text to each post row of a listed publication |
max_charge_usd | string | The run stops before it would charge more than this | |
proxy_mode | string | auto | auto (direct, then the Apify proxy for a host that refuses) or direct |
Every scalar input is accepted as a string, which is what Clay sends.
Output
One row layout for every row type, so no column is lost between them. Key fields:
| Field | Rows | Example |
|---|---|---|
row_type | all | publication, post, no_results, error |
publication_name, publication_url, author_name | all | Lenny's Newsletter, https://www.lennysnewsletter.com, Lenny Rachitsky |
subscriber_count_text, subscriber_count_min | all | Over 1,200,000 subscribers, 1200000 |
subscriber_tier_text, paid_subscriber_tier_text | all | Millions of subscribers, Tens of thousands of paid subscribers |
has_paid_plan, monthly_price, yearly_price, founding_price, price_currency | all | true, 20, 200, 400, USD |
post_title, post_url, post_date, post_type | post | How to tell if a startup has a moat, newsletter |
audience, is_paid | post | only_paid, true |
reaction_count, comment_count, restack_count, wordcount | post | 372, 2, 21, 4153 |
post_authors, post_tags, post_excerpt, body_text | post | Dan Hockenmaier, Career |
search_query | search rows | cold email |
row_status, error_reason, billable_events_json | all | ok, null, {"post-row":1} |
subscriber_count_min is the lower bound of what Substack shows (1.3K+ reads as 1300), not an exact count. A publication that hides its count leaves both subscriber fields empty.
The run summary (key-value store record RUN_SUMMARY) lists each publication and search with its row count and any note.
Pricing
Pay per event. You pay only these events; the Apify platform and proxy costs of your run are paid by Mamba Labs.
| Event | Free plan | Bronze | Silver | Gold |
|---|---|---|---|---|
Post row (post-row), one post | $0.00115 | $0.001093 | $0.001035 | $0.000977 |
Publication row (publication-row), one publication profile | $0.002 | $0.0019 | $0.0018 | $0.0017 |
Actor start (apify-actor-start), once per run | $0.001057 | $0.001057 | $0.001057 | $0.001057 |
Free rows: no_results and error rows, including the row a refused input returns. On the Apify free plan the actor stops at 1.50 USD of evaluation a month (about 1304 post rows); any paid Apify plan removes that cap.
Example: 10 publications with their 20 newest posts each is 10 publication rows ($0.02) plus 200 post rows ($0.23), $0.251 with the actor start.
Usage examples
Apify Console or API
{ "publications": ["lenny.substack.com", "https://www.notboring.co"], "max_posts_per_publication": "20" }
{ "search_queries": ["b2b marketing", "cold email"], "search_output": "publications", "max_search_results": "100" }
{ "publications": ["lenny"], "since_days": "30", "include_body": "true" }
Clay
Add an Apify column that sends a newsletter URL in publications with max_posts_per_publication set to 0, and read subscriber_count_min, has_paid_plan, and monthly_price from the publication row.
MCP
The MCP server @mambalabsdev/mcp-substack-scraper exposes this actor as a tool for Claude and other MCP clients.
Error handling
| Situation | What you get |
|---|---|
| The input has no publication and no query, or a value that cannot be read | One free row, row_status error, error_reason starting with input_invalid:. The run ends successfully and nothing is charged by this actor beyond the actor start |
| A site that is not a Substack publication | One free error row saying so |
| A publication refuses every route, or robots.txt disallows it | One free error row with row_status blocked |
| A search with no match | One free no_results row |
| Max charge reached | The run stops before the next billable row |
Limitations
- Subscriber counts are what Substack chooses to show: an exact homepage figure for some publications, a rounded figure (1.3K+) for others, and nothing for publications that hide it.
- Paid posts give only the free preview Substack shows to visitors.
- Substack search ranks by its own relevance and returns at most about 1,000 posts per query.
- Notes, comments text, and subscriber lists are not read.
- You are responsible for how you use the data and for Substack's terms.
More from Mamba Labs
Built by Mamba Labs.