Substack API Scraper: Posts, Authors & Newsletters
Pricing
from $0.50 / 1,000 posts
Substack API Scraper: Posts, Authors & Newsletters
Read public Substack posts, publications, and comments in structured rows. Browse archives, search posts, discover publications by topic or category, and read public recommendations. Get titles, authors, dates, engagement, public previews, and quality notes without a Substack login or API key.
Pricing
from $0.50 / 1,000 posts
Rating
0.0
(0)
Developer
Maxime Dupré
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
4 days ago
Last modified
Categories
Share
🧭 Public Substack data for research and archives
This Actor is for researchers, newsletter teams, analysts, and developers who need public Substack data. It returns structured post, publication, and comment rows with links, authors, dates, access status, engagement, discovery context, and quality notes. Use it to build a research table, check a publication, or collect a public post thread without manual copying.
- Read a publication archive with Substack API Posts.
- Retrieve public posts from their links with Substack Newsletter Scraper.
- Read a publication profile with Substack Publication Scraper.
- Search posts inside a publication with Substack API Search.
- Find publications by a topic with Substack Topic Discovery.
- Find ranked publications in a category with Substack Category Discovery.
- Find public publication data with Substack API Publications.
- Read Substack API Documentation before planning a public data workflow.
- Check Substack API Key guidance when choosing an access method.
- Try a general public-data run with Substack API.
🧾 See the Substack data you can use
Post rows hold public post identity, editorial fields, access status, author details, publication context, engagement, media, audio, and content when requested. Publication rows hold public identity, branding, setup details, and the category, topic, or recommendation value that led to the row. Comment rows hold public comment text, author details, time, engagement, depth, parent information, and post context.
The Actor reads public Substack surfaces. It does not need a Substack login or API key. Restricted posts keep public metadata and previews, while subscriber-only body content is not promised.
▶️ Choose a Substack task
How a run works
- Choose one target in the input form.
- Add the matching publication, post URL, category, topic, or post query.
- Add filters when you need a narrower set of posts.
- Turn on public article content only when you need HTML and readable text.
- Start the run, then open the dataset or the source-availability report.
Use one shared target and filter setup for each run. A list of same-kind publication targets is supported. Handles, Substack subdomain URLs, and supported custom-domain URLs can be used for publication targets.
⚙️ Input
Input fields
| Field | Type | What it does |
|---|---|---|
target | string | Required. Choose publicationArchive, post, publicationDetails, categoryDiscovery, topicDiscovery, publicationRecommendations, publicationSearch, or postComments. |
category | string | Required for categoryDiscovery. Enter the category used by Substack's public discovery view. |
ranking | string | Required for categoryDiscovery. Enter the ranking view used with the category. |
topic | string | Required for topicDiscovery. Enter free text for the public publication search. |
publicationTargets | array of strings | Add public publication handles, Substack subdomain URLs, or supported custom-domain URLs. Used by archive, details, recommendations, and publication search targets. For recommendations, each publication is the source. |
postUrls | array of objects | Add canonical public post URLs for post retrieval or comment threads. |
postUrls[].url | string | The full canonical public post URL. |
postQuery | string | Optional for publicationArchive and required for publicationSearch. Use text from a post title or subtitle. Other targets ignore it. |
dateFrom | string | Optional lower date bound for post targets. Use a UTC date in YYYY-MM-DD form. |
dateTo | string | Optional upper date bound for post targets. Use a UTC date in YYYY-MM-DD form. |
audience | string | Optional post filter. Choose all, free, or paid. Discovery and publication-details targets ignore it. |
languages | array of strings | Optional language filter for discovered publications and post results. Add language names or codes. Other targets ignore it. |
postTypes | array of strings | Optional post type filter. Choose newsletter, podcast, thread, or video. Non-post targets ignore it. |
authors | array of strings | Optional post filter. Add author names or public handles. Non-post targets ignore it. |
tags | array of strings | Optional post filter. Add publication tag names. Non-post targets ignore it. |
minReactions | integer | Optional minimum reaction count for post results. Non-post targets ignore it. |
minComments | integer | Optional minimum comment count for post results. Non-post targets ignore it. |
minWords | integer | Optional minimum word count for post results. Non-post targets ignore it. |
sortBy | string | Optional post order. Choose newest, oldest, popularity, engagement, or length. Targets that do not return posts ignore it. |
includeArticleContent | boolean | When true, fetch complete public article HTML and readable text when available. It applies to archive, post, and publication-search targets. Restricted posts still return public previews only. |
maxItems | integer | Optional positive limit on saved rows. It can stop archive, discovery, search, and comment work early. Leave it empty to return all available results until the source is exhausted. |
Default input
This is the complete public input from a successful current-beta default run:
{"target": "publicationArchive","publicationTargets": ["arxivblog"],"includeArticleContent": false}
🧾 Output
Output links
| Field | Type | What it does |
|---|---|---|
results | URL | Opens the default dataset with successful post, publication, and comment rows. |
sourceAvailability | URL | Opens the run report for unavailable sources and fetch failures. |
Every dataset row has a resultType value. The value is post, publication, or comment. The tables below cover each shape.
Post rows
| Field | Type | What it does |
|---|---|---|
resultType | string | Identifies this as a post row. |
post | object | Groups post identity, content, publication, and engagement data. |
post.id | string | Public post ID for joining or checking the source row, when available. |
post.url | string | Canonical public post URL. |
post.title | string | Public post title. |
post.description | string | Public subtitle or description, when available. |
post.publishedAt | string | Post publication time. |
post.postType | string | Source post type, such as newsletter, podcast, thread, or video. |
post.accessStatus | string | Says whether the post is public, paid, or otherwise restricted. |
post.authors | array of objects | Public post byline details. |
post.authors[] | object | One public post author. |
post.authors[].name | string | Public author name. |
post.authors[].handle | string | Public author handle, when available. |
post.authors[].id | string | Public author ID, when available. |
post.authors[].url | string | Public author profile URL, when available. |
post.publication | object | Publication context for the post. |
post.publication.id | string | Public publication ID, when available. |
post.publication.name | string | Public publication name. |
post.publication.handle | string | Public publication handle, when available. |
post.publication.url | string | Public publication URL. |
post.publication.domain | string | Publication domain, when available. |
post.publication.description | string | Public publication description, when available. |
post.publication.authors | array of objects | Available public publication authors. |
post.publication.authors[] | object | One public publication author. |
post.publication.authors[].name | string | Public publication author name. |
post.publication.authors[].handle | string | Public publication author handle, when available. |
post.publication.authors[].id | string | Public publication author ID, when available. |
post.publication.authors[].url | string | Public publication author profile URL, when available. |
post.publication.category | string | Publication category, when available. |
post.publication.language | string | Publication language or language code, when available. |
post.publication.branding | object | Public publication branding, when available. |
post.publication.branding.logoUrl | string | Public publication logo URL, when available. |
post.publication.branding.coverImageUrl | string | Public publication cover image URL, when available. |
post.publication.branding.accentColor | string | Publication accent color, when available. |
post.publication.setup | object | Public publication setup details, when available. |
post.publication.setup.subscriptionStatus | string | Public subscription status, when available. |
post.publication.setup.hasFoundingPlan | boolean | Whether a public founding plan is available, when shown. |
post.publication.setup.hasCommunity | boolean | Whether a public community is available, when shown. |
post.publication.setup.createdAt | string | Publication creation time, when available. |
post.engagement | object | Public post engagement counts and score, when available. |
post.engagement.reactionCount | integer | Number of post reactions, when available. |
post.engagement.commentCount | integer | Number of post comments, when available. |
post.engagement.restackCount | integer | Number of post restacks, when available. |
post.engagement.score | number | Aggregate source engagement measure, when available. |
post.reactionBreakdown | array of objects | Count for each reaction type exposed by the source. |
post.reactionBreakdown[] | object | One reaction type and count. |
post.reactionBreakdown[].type | string | Reaction type. |
post.reactionBreakdown[].count | integer | Count for that reaction type. |
post.wordCount | integer | Post word count, when available. |
post.language | string | Post language or language code, when available. |
post.media | object | Public cover and in-article image references, when available. |
post.media.coverImage | object | Cover image reference, when available. |
post.media.coverImage.url | string | Public cover image URL. |
post.media.coverImage.altText | string | Cover image alt text, when available. |
post.media.coverImage.caption | string | Cover image caption, when available. |
post.media.images | array of objects | In-article image references, when available. |
post.media.images[] | object | One in-article image reference. |
post.media.images[].url | string | Public in-article image URL. |
post.media.images[].altText | string | Image alt text, when available. |
post.media.images[].caption | string | Image caption, when available. |
post.audio | object | Audio details for an audio post, when available. |
post.audio.url | string | Public audio file URL. |
post.audio.durationSeconds | number | Audio duration in seconds, when available. |
post.content | object | Full public article or public preview, when available. |
post.content.html | string | Article HTML, when available. |
post.content.text | string | Readable article text, when available. |
post.content.isComplete | boolean | Says whether the content is the full public body instead of a preview. |
quality | object | Confidence and source-data warnings for the row. |
quality.confidence | string | Confidence level for the row fields. |
quality.warnings | array of strings | Notes about missing or uncertain source data. |
quality.warnings[] | string | One warning about missing or uncertain source data. |
Current-beta post row
{"resultType": "post","post": {"url": "https://arxivblog.substack.com/p/next-generation-ai-attack-vectors","title": "Next generation AI attack vectors will be ideas, say Anthropic researchers","publishedAt": "2026-08-21T17:08:27.058Z","postType": "newsletter","accessStatus": "public","id": "212161880","description": "Computer scientists have bred self-propagating \"mind viruses\" that spread from one AI agent to the next through ordinary conversation — no hacking required","authors": [{"name": "Physics arXiv Blog","handle": "physicsarxivblog","id": "75337004"}],"publication": {"name": "Emerging Technology from the arXiv","url": "https://arxivblog.substack.com/","id": "5026881","handle": "arxivblog","domain": "arxivblog.substack.com","description": "Technology. Science. Insight.","authors": [{"name": "Physics arXiv Blog","handle": "physicsarxivblog","id": "75337004"}],"language": "en","branding": {"logoUrl": "https://substackcdn.com/image/fetch/$s_!-WgM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3743002d-f5ed-4304-9f23-701618b0b1d2_1280x1280.png","accentColor": "#FF6719"},"setup": {"subscriptionStatus": "paid","hasFoundingPlan": true,"hasCommunity": true,"createdAt": "2025-05-15T12:12:29.439Z"}},"engagement": {"reactionCount": 30,"commentCount": 0,"restackCount": 13,"score": 43},"reactionBreakdown": [{"type": "❤","count": 30}],"wordCount": 1113,"language": "en","media": {"coverImage": {"url": "https://substackcdn.com/image/fetch/$s_!jAvp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F47f0a7f9-f2cd-4927-9bb6-539ad99de42d_550x665.png"}},"audio": {"url": "https://substack-video.s3.amazonaws.com/video_upload/post/212161880/tts/5cbb9c7b-74ce-4fe0-9b74-bd84b8e5cfde/en-GB-AdaMultilingualNeural.mp3"}},"quality": {"confidence": "high","warnings": []}}
Publication rows
| Field | Type | What it does |
|---|---|---|
resultType | string | Identifies this as a publication row. |
publication | object | Groups public publication identity, context, branding, and setup data. |
publication.id | string | Public publication ID, when available. |
publication.name | string | Public publication name. |
publication.handle | string | Public publication handle, when available. |
publication.url | string | Public publication URL. |
publication.domain | string | Publication domain, when available. |
publication.description | string | Public publication description, when available. |
publication.authors | array of objects | Available public publication authors. |
publication.authors[] | object | One public publication author. |
publication.authors[].name | string | Public author name. |
publication.authors[].handle | string | Public author handle, when available. |
publication.authors[].id | string | Public author ID, when available. |
publication.authors[].url | string | Public author profile URL, when available. |
publication.category | string | Publication category, when available. |
publication.language | string | Publication language or language code, when available. |
publication.branding | object | Public publication branding, when available. |
publication.branding.logoUrl | string | Public publication logo URL, when available. |
publication.branding.coverImageUrl | string | Public publication cover image URL, when available. |
publication.branding.accentColor | string | Publication accent color, when available. |
publication.setup | object | Public publication setup details, when available. |
publication.setup.subscriptionStatus | string | Public subscription status, when available. |
publication.setup.hasFoundingPlan | boolean | Whether a public founding plan is available, when shown. |
publication.setup.hasCommunity | boolean | Whether a public community is available, when shown. |
publication.setup.createdAt | string | Publication creation time, when available. |
discovery | object | The category, topic, or publication value that produced the row, when available. |
discovery.method | string | Discovery method, such as category, topic, or recommendation. |
discovery.value | string | Submitted category, topic, handle, or URL that produced the row. |
discovery.ranking | string | Category ranking view used for discovery, when applicable. |
quality | object | Confidence and source-data warnings for the row. |
quality.confidence | string | Confidence level for the row fields. |
quality.warnings | array of strings | Notes about missing or uncertain source data. |
quality.warnings[] | string | One warning about missing or uncertain source data. |
Current-beta publication row
{"resultType": "publication","publication": {"name": "Emerging Technology from the arXiv","url": "https://arxivblog.substack.com/","id": "5026881","handle": "arxivblog","domain": "arxivblog.substack.com","description": "Technology. Science. Insight.","authors": [{"name": "Physics arXiv Blog","handle": "physicsarxivblog","id": "75337004"}],"language": "en","branding": {"logoUrl": "https://substackcdn.com/image/fetch/$s_!-WgM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3743002d-f5ed-4304-9f23-701618b0b1d2_1280x1280.png","accentColor": "#FF6719"},"setup": {"subscriptionStatus": "paid","hasFoundingPlan": true,"hasCommunity": true,"createdAt": "2025-05-15T12:12:29.439Z"}},"quality": {"confidence": "high","warnings": []}}
Comment rows
| Field | Type | What it does |
|---|---|---|
resultType | string | Identifies this as a comment row. |
comment | object | Groups comment text, author, time, engagement, and thread relationship data. |
comment.id | string | Public comment ID, when available. |
comment.body | string | Public comment body. |
comment.createdAt | string | Time when the comment was posted. |
comment.author | object | Public comment author details, when available. |
comment.author.name | string | Public author name, when available. |
comment.author.handle | string | Public author handle, when available. |
comment.author.id | string | Public author ID, when available. |
comment.author.url | string | Public author profile URL, when available. |
comment.engagement | object | Public comment engagement counts and score, when available. |
comment.engagement.reactionCount | integer | Number of comment reactions, when available. |
comment.engagement.replyCount | integer | Number of direct replies, when available. |
comment.engagement.score | number | Aggregate source comment engagement measure, when available. |
comment.depth | integer | Comment depth in the thread. A root comment is 0. |
comment.parentId | string | Public parent comment ID, when this is a reply. |
comment.post | object | Public post that contains the comment. |
comment.post.id | string | Public post ID, when available. |
comment.post.title | string | Public post title, when available. |
comment.post.url | string | Canonical public post URL. |
comment.post.publication | object | Publication context for the commented post, when available. |
comment.post.publication.id | string | Public publication ID, when available. |
comment.post.publication.name | string | Public publication name. |
comment.post.publication.handle | string | Public publication handle, when available. |
comment.post.publication.url | string | Public publication URL. |
comment.post.publication.domain | string | Publication domain, when available. |
comment.post.publication.description | string | Public publication description, when available. |
comment.post.publication.authors | array of objects | Available public publication authors. |
comment.post.publication.authors[] | object | One public publication author. |
comment.post.publication.authors[].name | string | Public author name. |
comment.post.publication.authors[].handle | string | Public author handle, when available. |
comment.post.publication.authors[].id | string | Public author ID, when available. |
comment.post.publication.authors[].url | string | Public author profile URL, when available. |
comment.post.publication.category | string | Publication category, when available. |
comment.post.publication.language | string | Publication language or language code, when available. |
comment.post.publication.branding | object | Public publication branding, when available. |
comment.post.publication.branding.logoUrl | string | Public publication logo URL, when available. |
comment.post.publication.branding.coverImageUrl | string | Public publication cover image URL, when available. |
comment.post.publication.branding.accentColor | string | Publication accent color, when available. |
comment.post.publication.setup | object | Public publication setup details, when available. |
comment.post.publication.setup.subscriptionStatus | string | Public subscription status, when available. |
comment.post.publication.setup.hasFoundingPlan | boolean | Whether a public founding plan is available, when shown. |
comment.post.publication.setup.hasCommunity | boolean | Whether a public community is available, when shown. |
comment.post.publication.setup.createdAt | string | Publication creation time, when available. |
quality | object | Confidence and source-data warnings for the row. |
quality.confidence | string | Confidence level for the row fields. |
quality.warnings | array of strings | Notes about missing or uncertain source data. |
quality.warnings[] | string | One warning about missing or uncertain source data. |
Current-beta comment row
{"resultType": "comment","comment": {"body": "Yep! Spec decoding doesn't reduce the work, it just converts memory-bound idle time into tokens i.e. compute you'd already paid for.","createdAt": "2026-08-26T19:35:43.743Z","depth": 0,"post": {"url": "https://blog.bytebytego.com/p/how-to-make-llms-3x-faster","id": "212180385","title": "How to Make LLMs 3X Faster","publication": {"name": "ByteByteGo Newsletter","url": "https://blog.bytebytego.com/","id": "817132","handle": "bytebytego","domain": "blog.bytebytego.com","description": "Explain complex systems with simple terms, from the authors of the best-selling system design book series. Join over 1,000,000 friendly readers.","authors": [{"name": "Alex Xu","handle": "bytebytego","id": "22329494"},{"name": "Sahn Lam","handle": "sahnlam","id": "55391021"},{"name": "ByteByteGo","handle": "bytebytego399569","id": "106455990"}],"language": "en","branding": {"logoUrl": "https://substackcdn.com/image/fetch/$s_!1eXV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F8a5609ae-1239-4400-9491-6010a15c4d60_504x504.png","coverImageUrl": "https://substack-post-media.s3.amazonaws.com/public/images/a4e1c1bd-03ee-4126-b3e4-19553b2d2fc6_1279x821.png","accentColor": "#9D6FFF"},"setup": {"subscriptionStatus": "paid","hasFoundingPlan": true,"hasCommunity": true,"createdAt": "2022-03-27T03:36:45.845Z"}}},"id": "323271360","author": {"name": "Mitchell Kosowski","handle": "mitchellkosowski","id": "803879"},"engagement": {"reactionCount": 0,"replyCount": 0,"score": 1}},"quality": {"confidence": "high","warnings": []}}
💳 Pricing
How billing works
Pricing is pay per event. An event is charged when the matching public row is saved. The exact rate depends on the event and the Apify plan tier.
| Event | Charge |
|---|---|
substack-post-retrieved | One saved public post. The rates are $0.0018 on FREE, $0.0009 on BRONZE, $0.0007 on SILVER, $0.0005 on GOLD, $0.00035 on PLATINUM, and $0.00025 on DIAMOND. |
substack-publication-retrieved | One saved public publication at $0.0018. |
substack-comment-retrieved | One saved public comment at $0.0018. |
Use filters and maxItems to limit the rows a run can save. Leaving maxItems empty returns all available results until the source is exhausted. This pricing explanation does not assume a charge for an empty or no-result run.
🔌 Integrations
Dataset access
Start the Actor in Apify Console or through the standard Actor API. Open the dataset after the run to review rows or export them in the formats provided by Apify.
Video guide
❓ FAQ
What happens with a paid or restricted post?
The Actor returns public identity, access status, metadata, and a public preview when the source provides one. It does not promise subscriber-only body content.
How do I search posts inside a publication?
Choose publicationSearch, add a publication target, and enter postQuery. The query uses text found in post titles or subtitles. You can also add the post filters that apply to the target.
How do I discover publications by topic or category?
Choose topicDiscovery and enter a topic, or choose categoryDiscovery and enter a category with its ranking view. You can also choose publicationRecommendations to read public recommendations from a publication target.
Can I retrieve one post by URL?
Yes. Choose post, add its canonical public URL to postUrls, and set any post filters you need.
Can I return all available rows?
Yes. Leave maxItems empty. The Actor continues until all available results are returned or the source is exhausted.
Can I read public comments?
Yes. Choose postComments and add one or more canonical public post URLs. Comment rows can include body, author, time, engagement, depth, and parent comment ID when the source provides them.
What if a source is unavailable?
Open the sourceAvailability report from the output. It provides a place to review unavailable sources and fetch failures separately from successful rows.
Can I use more than one publication target?
Yes. Add a list of same-kind public publication targets for archive, details, recommendations, or publication search work. The same filters apply to the whole run.
Do I need a Substack login or API key?
No. The Actor reads public Substack data without a login or API key. Public availability and source changes can still affect what a run returns.
How can I reduce the work in a run?
Use postQuery, date, language, audience, post type, author, tag, engagement, and word-count filters when they fit your target. Set maxItems when you need a smaller result set, and leave article content off unless you need the public body.
📝 Changelog
0.0: Initial release
🆘 Support
For issues, questions, or feature requests, file a ticket and I'll fix or implement it in less than 24h 🫡
🔗 Related Actors
- Substack Notes Scraper collects public Notes for topic and author research alongside newsletter data.
- Substack Recommendations maps public recommendation links between publications.
- Substack API & Scraper — Posts, Authors & Newsletters provides another post, author, and newsletter archive workflow.
- Substack Scraper - Newsletters, Posts & Authors collects newsletter posts and author data for comparison work.
- Substack Scraper — Posts, Comments & Newsletters covers post, comment, and newsletter research workflows.
Made with ❤️ by Maxime Dupré